diff --git a/src/linux_tcp/sslconnected.h b/src/linux_tcp/sslconnected.h index 1acb052..6b773a4 100644 --- a/src/linux_tcp/sslconnected.h +++ b/src/linux_tcp/sslconnected.h @@ -161,14 +161,11 @@ private: /** * Method to repeat the previous call\ * @param monitor monitor to check if connection object still exists - * @param result result of an earlier openssl operation + * @param result result of an earlier SSL_get_error call * @return TcpState* */ - TcpState *repeat(const Monitor &monitor, int result) + TcpState *repeat(const Monitor &monitor, int error) { - // error was returned, so we must investigate what is going on - auto error = OpenSSL::SSL_get_error(_ssl, result); - // check the error switch (error) { case SSL_ERROR_WANT_READ: @@ -305,7 +302,7 @@ public: if (result > 0) return proceed(); // the operation failed, we may have to repeat our call - else return repeat(monitor, result); + else return repeat(monitor, OpenSSL::SSL_get_error(_ssl, result)); } else { @@ -316,7 +313,7 @@ public: if (result > 0) return parse(monitor, result); // the operation failed, we may have to repeat our call - else return repeat(monitor, result); + else return repeat(monitor, OpenSSL::SSL_get_error(_ssl, result)); } } @@ -339,18 +336,35 @@ public: // try to send more data from the outgoing buffer auto result = _out.sendto(_ssl); - // go to the next state - auto *state = result > 0 ? proceed() : repeat(monitor, result); - - return state; - -// if (result > 0) return proceed(); -// -// // the operation failed, we may have to repeat our call -// else return repeat(result); + // was this a success? + if (result > 0) + { + // parse the buffer + auto *nextstate = parse(monitor, result); + + // leap out if we move to a different state + if (nextstate != this) return nextstate; + } + else + { + // error was returned, so we must investigate what is going on + auto error = OpenSSL::SSL_get_error(_ssl, result); + + // get the next state given this error + auto *nextstate = repeat(monitor, error); + + // leap out if we move to a different state + if (nextstate != this) return nextstate; + + // check the type of error, and wait now + switch (error) { + case SSL_ERROR_WANT_READ: wait.readable(); break; + case SSL_ERROR_WANT_WRITE: wait.active(); break; + } + } } - + // done return this; } diff --git a/src/linux_tcp/sslshutdown.h b/src/linux_tcp/sslshutdown.h index 4131a52..67da802 100644 --- a/src/linux_tcp/sslshutdown.h +++ b/src/linux_tcp/sslshutdown.h @@ -42,6 +42,32 @@ private: bool _finalized; + /** + * Report an error + * @param monitor object to check if connection still exists + * @return TcpState* + */ + TcpState *reporterror(const Monitor &monitor) + { + // close the socket + close(_socket); + + // forget the socket + _socket = -1; + + // if we have already told user space that connection is gone + if (_finalized) return new TcpClosed(this); + + // object will be finalized now + _finalized = true; + + // inform user space that the party is over + _handler->onError(_connection, "ssl shutdown error"); + + // go to the final state (if not yet disconnected) + return monitor.valid() ? new TcpClosed(this) : nullptr; + } + /** * Proceed with the next operation after the previous operation was * a success, possibly changing the filedescriptor-monitor @@ -96,17 +122,8 @@ private: return this; default: - // the shutdown failed, ignore this if user was already notified of an error - if (_finalized) return new TcpClosed(this); - - // object will be finalized now - _finalized = true; - - // inform user space that the party is over - _handler->onError(_connection, "ssl shutdown error"); - // go to the final state (if not yet disconnected) - return monitor.valid() ? new TcpClosed(this) : nullptr; + return reporterror(monitor); } } @@ -172,6 +189,42 @@ public: // the operation failed, we may have to repeat our call else return repeat(monitor, result); } + + /** + * Flush the connection, sent all buffered data to the socket + * @param monitor Object to check if connection still exists + * @return TcpState new tcp state + */ + virtual TcpState *flush(const Monitor &monitor) override + { + // create an object to wait for the filedescriptor to becomes active + Wait wait(_socket); + + // keep looping + while (true) + { + // close the connection + auto result = OpenSSL::SSL_shutdown(_ssl); + + // if this is a success, we can proceed with the event loop + if (result > 0) return proceed(monitor); + + // error was returned, so we must investigate what is going on + auto error = OpenSSL::SSL_get_error(_ssl, result); + + // check the error + switch (error) { + + // if openssl reports that socket readability or writability is needed, + // we wait for that until this situation is reached + case SSL_ERROR_WANT_READ: wait.readable(); break; + case SSL_ERROR_WANT_WRITE: wait.active(); break; + + // something is wrong, we proceed to the next state + default: return reporterror(monitor); + } + } + } }; /**