ssl connection fixes

This commit is contained in:
Emiel Bruijntjes 2018-03-08 13:36:56 +01:00
parent 872d4e9a11
commit e39ca5b012
4 changed files with 53 additions and 38 deletions

View File

@ -14,6 +14,7 @@
#include <amqpcpp.h> #include <amqpcpp.h>
#include <amqpcpp/libev.h> #include <amqpcpp/libev.h>
#include <openssl/ssl.h> #include <openssl/ssl.h>
#include <openssl/opensslv.h>
/** /**
* Custom handler * Custom handler
@ -66,7 +67,11 @@ int main()
MyHandler handler(loop); MyHandler handler(loop);
// init the SSL library // init the SSL library
// SSL_library_init(); #if OPENSSL_VERSION_NUMBER < 0x10100000L
SSL_library_init();
#else
OPENSSL_init_ssl(0, NULL);
#endif
// make a connection // make a connection
AMQP::Address address("amqp://guest:guest@localhost/"); AMQP::Address address("amqp://guest:guest@localhost/");

View File

@ -139,11 +139,14 @@ private:
} }
else if (_closed) else if (_closed)
{ {
// start the state that closes the connection
auto *nextstate = new SslShutdown(_connection, _socket, std::move(_ssl), _finalized, _handler);
// we forget the current socket to prevent that it gets destructed // we forget the current socket to prevent that it gets destructed
_socket = -1; _socket = -1;
// start the state that closes the connection // report the next state
return new SslShutdown(_connection, _socket, std::move(_ssl), _finalized, _handler); return nextstate;
} }
else else
{ {
@ -263,7 +266,7 @@ public:
{ {
// tell the handler to monitor the socket if there is an out // tell the handler to monitor the socket if there is an out
_handler->monitor(_connection, _socket, _state == state_sending ? readable | writable : readable); _handler->monitor(_connection, _socket, _state == state_sending ? readable | writable : readable);
} }
/** /**
* Destructor * Destructor

View File

@ -122,7 +122,7 @@ public:
_ssl(SslContext(OpenSSL::TLS_client_method())), _ssl(SslContext(OpenSSL::TLS_client_method())),
_socket(socket), _socket(socket),
_out(std::move(buffer)) _out(std::move(buffer))
{ {
// we will be using the ssl context as a client // we will be using the ssl context as a client
OpenSSL::SSL_set_connect_state(_ssl); OpenSSL::SSL_set_connect_state(_ssl);
@ -168,13 +168,13 @@ public:
// start the ssl handshake // start the ssl handshake
int result = OpenSSL::SSL_do_handshake(_ssl); int result = OpenSSL::SSL_do_handshake(_ssl);
// if the connection succeeds, we can move to the ssl-connected state // if the connection succeeds, we can move to the ssl-connected state
if (result == 1) return nextstate(new SslConnected(_connection, _socket, std::move(_ssl), std::move(_out), _handler)); if (result == 1) return nextstate(new SslConnected(_connection, _socket, std::move(_ssl), std::move(_out), _handler));
// error was returned, so we must investigate what is going on // error was returned, so we must investigate what is going on
auto error = OpenSSL::SSL_get_error(_ssl, result); auto error = OpenSSL::SSL_get_error(_ssl, result);
// check the error // check the error
switch (error) { switch (error) {
case SSL_ERROR_WANT_READ: return proceed(readable); case SSL_ERROR_WANT_READ: return proceed(readable);
@ -217,15 +217,15 @@ public:
auto error = OpenSSL::SSL_get_error(_ssl, result); auto error = OpenSSL::SSL_get_error(_ssl, result);
// check the error // check the error
switch (error) switch (error) {
{
// if openssl reports that socket readability or writability is needed, // if openssl reports that socket readability or writability is needed,
// we wait for that until this situation is reached // we wait for that until this situation is reached
case SSL_ERROR_WANT_READ: wait.readable(); break; case SSL_ERROR_WANT_READ: wait.readable(); break;
case SSL_ERROR_WANT_WRITE: wait.active(); break; case SSL_ERROR_WANT_WRITE: wait.active(); break;
// something is wrong, we proceed to the next state // something is wrong, we proceed to the next state
default: return reportError(monitor); default: return reportError(monitor);
} }
} }
} }

View File

@ -42,6 +42,28 @@ private:
bool _finalized; bool _finalized;
/**
* Close the socket
* @return bool
*/
bool close()
{
// skip if already closed
if (_socket < 0) return false;
// we're no longer interested in events
_handler->monitor(_connection, _socket, 0);
// close the socket
::close(_socket);
// forget the socket
_socket = -1;
// done
return true;
}
/** /**
* Report an error * Report an error
* @param monitor object to check if connection still exists * @param monitor object to check if connection still exists
@ -50,10 +72,7 @@ private:
TcpState *reporterror(const Monitor &monitor) TcpState *reporterror(const Monitor &monitor)
{ {
// close the socket // close the socket
close(_socket); close();
// forget the socket
_socket = -1;
// if we have already told user space that connection is gone // if we have already told user space that connection is gone
if (_finalized) return new TcpClosed(this); if (_finalized) return new TcpClosed(this);
@ -76,14 +95,8 @@ private:
*/ */
TcpState *proceed(const Monitor &monitor) TcpState *proceed(const Monitor &monitor)
{ {
// we're no longer interested in events
_handler->monitor(_connection, _socket, 0);
// close the socket // close the socket
close(_socket); close();
// forget the socket
_socket = -1;
// if we have already told user space that connection is gone // if we have already told user space that connection is gone
if (_finalized) return new TcpClosed(this); if (_finalized) return new TcpClosed(this);
@ -108,7 +121,7 @@ private:
{ {
// error was returned, so we must investigate what is going on // error was returned, so we must investigate what is going on
auto error = OpenSSL::SSL_get_error(_ssl, result); auto error = OpenSSL::SSL_get_error(_ssl, result);
// check the error // check the error
switch (error) { switch (error) {
case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_READ:
@ -143,8 +156,8 @@ public:
_socket(socket), _socket(socket),
_finalized(finalized) _finalized(finalized)
{ {
// tell the handler to monitor the socket if there is an out // wait until the socket is accessible
_handler->monitor(_connection, _socket, readable); _handler->monitor(_connection, _socket, readable | writable);
} }
/** /**
@ -152,14 +165,8 @@ public:
*/ */
virtual ~SslShutdown() noexcept virtual ~SslShutdown() noexcept
{ {
// skip if socket is already gond
if (_socket < 0) return;
// we no longer have to monitor the socket
_handler->monitor(_connection, _socket, 0);
// close the socket // close the socket
close(_socket); close();
} }
/** /**
@ -182,7 +189,7 @@ public:
// close the connection // close the connection
auto result = OpenSSL::SSL_shutdown(_ssl); auto result = OpenSSL::SSL_shutdown(_ssl);
// if this is a success, we can proceed with the event loop // if this is a success, we can proceed with the event loop
if (result > 0) return proceed(monitor); if (result > 0) return proceed(monitor);