support for amqps:// addresses in the AMQP::Address class (although it does not yet make a real secure connection)

This commit is contained in:
Tamas Elekes 2018-03-02 13:53:00 +01:00
parent ab817384b1
commit 342268e50a
3 changed files with 44 additions and 23 deletions

View File

@ -23,12 +23,11 @@ namespace AMQP {
class Address class Address
{ {
private: private:
/** /**
* The auth method * The auth method
* @var std::string * @var bool
*/ */
std::string _authmethod; bool _secure;
/** /**
* Login data (username + password) * Login data (username + password)
@ -68,12 +67,12 @@ public:
const char *last = data + size; const char *last = data + size;
// must start with amqp:// or ampqs:// // must start with amqp:// or ampqs://
if (strncmp(data, "amqps://", 8) == 0) _authmethod = std::string("amqps://"); if (strncmp(data, "amqps://", 8) == 0) _secure = true;
else if (strncmp(data, "amqp://", 7) == 0) _authmethod = std::string("amqp://"); else if (strncmp(data, "amqp://", 7) == 0) _secure = false;
else throw std::runtime_error("AMQP address should start with \"amqp://\" or \"amqps://\""); else throw std::runtime_error("AMQP address should start with \"amqp://\" or \"amqps://\"");
// begin of the string was parsed // begin of the string was parsed
data += _authmethod.length(); data += _secure ? 8 : 7;
// do we have a '@' to split user-data and hostname? // do we have a '@' to split user-data and hostname?
const char *at = (const char *)memchr(data, '@', last - data); const char *at = (const char *)memchr(data, '@', last - data);
@ -138,14 +137,14 @@ public:
/** /**
* Constructor based on already known properties * Constructor based on already known properties
* @param authmethod
* @param host * @param host
* @param port * @param port
* @param login * @param login
* @param vhost * @param vhost
* @param secure
*/ */
Address(std::string authmethod, std::string host, uint16_t port, Login login, std::string vhost) : Address(std::string host, uint16_t port, Login login, std::string vhost, bool secure = false) :
_authmethod(std::move(authmethod)), _secure(secure),
_login(std::move(login)), _login(std::move(login)),
_hostname(std::move(host)), _hostname(std::move(host)),
_port(port), _port(port),
@ -157,12 +156,12 @@ public:
virtual ~Address() = default; virtual ~Address() = default;
/** /**
* Expose the login data * Should we open a secure connection?
* @return Login * @return bool
*/ */
const std::string &authmethod() const bool secure() const
{ {
return _authmethod; return _secure;
} }
/** /**
@ -208,7 +207,7 @@ public:
operator std::string () const operator std::string () const
{ {
// result object // result object
std::string str(_authmethod); std::string str(_secure ? "amqps://" : "amqp://");
// append login // append login
str.append(_login.user()).append(":").append(_login.password()).append("@").append(_hostname); str.append(_login.user()).append(":").append(_login.password()).append("@").append(_hostname);
@ -233,8 +232,8 @@ public:
*/ */
bool operator==(const Address &that) const bool operator==(const Address &that) const
{ {
// auth method should match // security setting should match
if (_authmethod != that._authmethod) return false; if (_secure != that._secure) return false;
// logins must match // logins must match
if (_login != that._login) return false; if (_login != that._login) return false;
@ -267,8 +266,8 @@ public:
*/ */
bool operator<(const Address &that) const bool operator<(const Address &that) const
{ {
// compare auth methods // compare auth methods (amqp comes before amqps)
if (_authmethod != that._authmethod) return _authmethod < that._authmethod; if (_secure != that._secure) return !_secure;
// compare logins // compare logins
if (_login != that._login) return _login < that._login; if (_login != that._login) return _login < that._login;
@ -295,7 +294,7 @@ public:
friend std::ostream &operator<<(std::ostream &stream, const Address &address) friend std::ostream &operator<<(std::ostream &stream, const Address &address)
{ {
// start with the protocol and login // start with the protocol and login
stream << address._authmethod << address._login; stream << (address._secure ? "amqps://" : "amqp://");
// do we need a special portnumber? // do we need a special portnumber?
if (address._port != 5672) stream << ":" << address._port; if (address._port != 5672) stream << ":" << address._port;

View File

@ -24,7 +24,7 @@ namespace AMQP {
* @param hostname The address to connect to * @param hostname The address to connect to
*/ */
TcpConnection::TcpConnection(TcpHandler *handler, const Address &address) : TcpConnection::TcpConnection(TcpHandler *handler, const Address &address) :
_state(new TcpResolver(this, address.hostname(), address.port(), handler)), _state(new TcpResolver(this, address.hostname(), address.port(), address.secure(), handler)),
_connection(this, address.login(), address.vhost()) {} _connection(this, address.login(), address.vhost()) {}
/** /**

View File

@ -39,6 +39,12 @@ private:
*/ */
std::string _hostname; std::string _hostname;
/**
* Should we be using a secure connection?
* @var bool
*/
bool _secure;
/** /**
* The portnumber to connect to * The portnumber to connect to
* @var uint16_t * @var uint16_t
@ -142,11 +148,13 @@ public:
* @param connection Parent connection object * @param connection Parent connection object
* @param hostname The hostname for the lookup * @param hostname The hostname for the lookup
* @param portnumber The portnumber for the lookup * @param portnumber The portnumber for the lookup
* @param secure Do we need a secure tls connection when ready?
* @param handler User implemented handler object * @param handler User implemented handler object
*/ */
TcpResolver(TcpConnection *connection, const std::string &hostname, uint16_t port, TcpHandler *handler) : TcpResolver(TcpConnection *connection, const std::string &hostname, uint16_t port, bool secure, TcpHandler *handler) :
TcpState(connection, handler), TcpState(connection, handler),
_hostname(hostname), _hostname(hostname),
_secure(secure),
_port(port) _port(port)
{ {
// tell the event loop to monitor the filedescriptor of the pipe // tell the event loop to monitor the filedescriptor of the pipe
@ -183,7 +191,14 @@ public:
if (fd != _pipe.in() || !(flags & readable)) return this; if (fd != _pipe.in() || !(flags & readable)) return this;
// do we have a valid socket? // do we have a valid socket?
if (_socket >= 0) return new TcpConnected(_connection, _socket, std::move(_buffer), _handler); if (_socket >= 0)
{
// if we need a secure connection, we move to the tls handshake
//if (_secure) return new TcpSslHandshake(....);
// otherwise we have a valid regular tcp connection
return new TcpConnected(_connection, _socket, std::move(_buffer), _handler);
}
// report error // report error
_handler->onError(_connection, _error.data()); _handler->onError(_connection, _error.data());
@ -202,7 +217,14 @@ public:
_thread.join(); _thread.join();
// do we have a valid socket? // do we have a valid socket?
if (_socket >= 0) return new TcpConnected(_connection, _socket, std::move(_buffer), _handler); if (_socket >= 0)
{
// if we need a secure connection, we move to the tls handshake
//if (_secure) return new TcpSslHandshake(....);
// otherwise we have a valid regular tcp connection
return new TcpConnected(_connection, _socket, std::move(_buffer), _handler);
}
// report error // report error
_handler->onError(_connection, _error.data()); _handler->onError(_connection, _error.data());