implemented flushing for ssl connections

This commit is contained in:
Emiel Bruijntjes 2018-03-08 13:09:56 +01:00
parent bc4db8d8fe
commit 872d4e9a11
2 changed files with 94 additions and 27 deletions

View File

@ -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;
}

View File

@ -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);
}
}
}
};
/**