aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--kike.c26
1 files changed, 24 insertions, 2 deletions
diff --git a/kike.c b/kike.c
index 258c088..e2aca2d 100644
--- a/kike.c
+++ b/kike.c
@@ -311,6 +311,7 @@ struct client
bool initialized; ///< Has any data been received yet?
bool registered; ///< The user has registered
bool closing_link; ///< Closing link
+ bool half_closed; ///< Closing link: conn. is half-closed
bool ssl_rx_want_tx; ///< SSL_read() wants to write
bool ssl_tx_want_rx; ///< SSL_write() wants to read
@@ -787,7 +788,9 @@ client_kill (struct client *c, const char *reason)
struct server_context *ctx = c->ctx;
if (c->ssl)
+ // Note that we might have already called this once, but that is fine
(void) SSL_shutdown (c->ssl);
+
xclose (c->socket_fd);
c->socket_event.closed = true;
@@ -2620,8 +2623,27 @@ on_client_ready (const struct pollfd *pfd, void *user_data)
client_update_poller (c, pfd);
// The purpose of the `closing_link' state is to transfer the `ERROR'
- if (c->closing_link && !c->write_buffer.len)
- client_kill (c, NULL);
+ if (c->closing_link && !c->half_closed && !c->write_buffer.len)
+ {
+ // To make sure the client has received our ERROR message, we must
+ // first half-close the connection, otherwise it could happen that they
+ // receive a RST from our TCP stack first when we receive further data
+
+ // We only send the "close notify" alert if libssl can write to the
+ // socket at this moment. All the other data has been already written,
+ // though, and the client will receive a TCP half-close as usual, so
+ // it's not that important if the alert actually gets through.
+ if (c->ssl)
+ (void) SSL_shutdown (c->ssl);
+
+ // Either the shutdown succeeds, in which case we set a flag so that
+ // we don't retry this action and wait until we get an EOF, or it fails
+ // and we just kill the client straight away
+ if (!shutdown (c->socket_fd, SHUT_WR))
+ c->half_closed = true;
+ else
+ client_kill (c, NULL);
+ }
}
static void