/** * Class describing initial connection setup * * This frame is sent by the server to the client, right after the connection * is opened. It contains the initial connection properties, and the protocol * number. * * @copyright 2014 - 2023 Copernica BV */ /** * Dependencies */ #include "programname.h" #include "platformname.h" /** * Cause we want to print out version string that is passed to compiled with -D * flag. Why 2 macros? https://www.guyrutenberg.com/2008/12/20/expanding-macros-into-string-constants-in-c/ */ #define STR_EXPAND(s) #s #define STR(s) STR_EXPAND(s) /** * The version and distro names */ #define VERSION_NAME STR(VERSION) /** * Set up namespace */ namespace AMQP { /** * Class implementation */ class ConnectionStartFrame : public ConnectionFrame { private: /** * Major AMQP version number * @var uint8_t */ uint8_t _major; /** * Minor AMQP version number * @var uint8_t */ uint8_t _minor; /** * Additional server properties * @note: exact properties are not specified * and are implementation-dependent * @var Table */ Table _properties; /** * Available security mechanisms * @var LongString */ LongString _mechanisms; /** * Available message locales * @var LongString */ LongString _locales; protected: /** * Encode a frame on a string buffer * * @param buffer buffer to write frame to */ virtual void fill(OutBuffer& buffer) const override { // call base ConnectionFrame::fill(buffer); // encode all fields buffer.add(_major); buffer.add(_minor); _properties.fill(buffer); _mechanisms.fill(buffer); _locales.fill(buffer); } public: /** * Client-side constructer for a connection start frame * * @param major major protocol version * @param minor minor protocol version * @param properties server properties * @param mechanisms available security mechanisms * @param locales available locales */ ConnectionStartFrame(uint8_t major, uint8_t minor, const Table& properties, const std::string& mechanisms, const std::string& locales) : ConnectionFrame((uint32_t)(properties.size() + mechanisms.length() + locales.length() + 10)), // 4 for each longstring (size-uint32), 2 major/minor _major(major), _minor(minor), _properties(properties), _mechanisms(mechanisms), _locales(locales) {} /** * Construct a connection start frame from a received frame * * @param frame received frame */ ConnectionStartFrame(ReceivedFrame &frame) : ConnectionFrame(frame), _major(frame.nextUint8()), _minor(frame.nextUint8()), _properties(frame), _mechanisms(frame), _locales(frame) {} /** * Destructor */ virtual ~ConnectionStartFrame() {} /** * Method id * @return uint16_t */ virtual uint16_t methodID() const override { return 10; } /** * Major AMQP version number * @return uint8_t */ uint8_t majorVersion() const { return _major; } /** * Minor AMQP version number * @return uint8_t */ uint8_t minorVersion() const { return _minor; } /** * Additional server properties * @note: exact properties are not specified * and are implementation-dependent * * @return Table */ const Table& properties() const { return _properties; } /** * The capabilities of the connection * @return Table */ const Table& capabilities() const { // retrieve the capabilities return _properties.get("capabilities"); } /** * Available security mechanisms * @return string */ const std::string &mechanisms() const { return _mechanisms; } /** * Available message locales * @return string */ const std::string &locales() const { return _locales; } /** * Process the connection start frame * @param connection * @return bool * @internal */ virtual bool process(ConnectionImpl *connection) override { // the client properties Table properties; // move connection to handshake mode connection->setProtocolOk(_properties, properties); // the capabilities Table capabilities; // we want a special treatment for authentication failures capabilities["authentication_failure_close"] = true; // when the server cancels a consumer (for example because a queue is delete, or the node on which the // queue lives dies, we want to receive a notification that the consumer is no longer alive) capabilities["consumer_cancel_notify"] = true; // fill the peer properties if (!properties.contains("product")) properties["product"] = ProgramName(); if (!properties.contains("version")) properties["version"] = "AMQP-CPP " VERSION_NAME; if (!properties.contains("platform")) properties["platform"] = PlatformName(); if (!properties.contains("copyright")) properties["copyright"] = "Copernica AMQP-CPP library :: Copyright 2015-2023 Copernica BV"; if (!properties.contains("information")) properties["information"] = "https://github.com/CopernicaMarketingSoftware/AMQP-CPP"; if (!properties.contains("capabilities")) properties["capabilities"] = capabilities; // send back a connection start ok frame connection->send(ConnectionStartOKFrame(properties, "PLAIN", connection->login().saslPlain(), "en_US")); // done return true; } }; /** * end namespace */ }