diff options
author | Přemysl Janouch <p.janouch@gmail.com> | 2015-03-23 22:57:13 +0100 |
---|---|---|
committer | Přemysl Janouch <p.janouch@gmail.com> | 2015-03-23 22:57:13 +0100 |
commit | 94d4f060ff7856b28489911dc2be07060d23451e (patch) | |
tree | 92e45465c917e3936d801f69dbc3d60f509d0070 /kike.c | |
parent | 2dd191376f90a93be527cdc8beeb80173dba5309 (diff) | |
download | xK-94d4f060ff7856b28489911dc2be07060d23451e.tar.gz xK-94d4f060ff7856b28489911dc2be07060d23451e.tar.xz xK-94d4f060ff7856b28489911dc2be07060d23451e.zip |
kike: be more careful when closing the connection
Diffstat (limited to 'kike.c')
-rw-r--r-- | kike.c | 26 |
1 files changed, 24 insertions, 2 deletions
@@ -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 |