diff --git a/CMakeLists.txt b/CMakeLists.txt index b5ac66f..69deeaf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,9 +24,11 @@ option(AMQP-CPP_BUILD_SHARED "Build shared library. If off, build will be static option(AMQP-CPP_LINUX_TCP "Build linux sockets implementation." OFF) option(AMQP-CPP_BUILD_EXAMPLES "Build amqpcpp examples" OFF) +# pass version number to source files as macro +add_compile_definitions(VERSION=${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) + # ensure c++11 on all compilers -set (CMAKE_CXX_STANDARD 17 -) +set (CMAKE_CXX_STANDARD 17) # add source files # ------------------------------------------------------------------------------------------------------ diff --git a/Makefile b/Makefile index d460001..6f9254c 100644 --- a/Makefile +++ b/Makefile @@ -6,19 +6,19 @@ export SONAME = 4.3 export VERSION = 4.3.24 all: - $(MAKE) -C src all + $(MAKE) VERSION=${VERSION} -C src all pure: - $(MAKE) -C src pure + $(MAKE) VERSION=${VERSION} -C src pure release: - $(MAKE) -C src release + $(MAKE) VERSION=${VERSION} -C src release static: - $(MAKE) -C src static + $(MAKE) VERSION=${VERSION} -C src static shared: - $(MAKE) -C src shared + $(MAKE) VERSION=${VERSION} -C src shared clean: $(MAKE) -C src clean diff --git a/src/Makefile b/src/Makefile index c8c4401..d96674e 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,6 +1,6 @@ CPP = g++ RM = rm -f -CPPFLAGS = -Wall -c -I../include -std=c++17 -MD -Wno-class-conversion +CPPFLAGS = -Wall -c -I../include -std=c++17 -MD -Wno-class-conversion -DVERSION=${VERSION} LD = g++ LD_FLAGS = -Wall -shared SHARED_LIB = lib$(LIBRARY_NAME).so.$(VERSION) diff --git a/src/connectionstartframe.h b/src/connectionstartframe.h index a203046..6c1d46b 100644 --- a/src/connectionstartframe.h +++ b/src/connectionstartframe.h @@ -5,9 +5,29 @@ * is opened. It contains the initial connection properties, and the protocol * number. * - * @copyright 2014 - 2022 Copernica BV + * @copyright 2014 - 2023 Copernica BV */ +/** + * Dependencies + */ +#if !defined(_WIN32) && !defined(_WIN64) +#include "programname.h" +#include "platformname.h" +#endif + +/** + * 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 */ @@ -200,19 +220,28 @@ public: capabilities["consumer_cancel_notify"] = true; // fill the peer properties - if (!properties.contains("product")) properties["product"] = "Copernica AMQP library"; - if (!properties.contains("version")) properties["version"] = "Unknown"; - if (!properties.contains("platform")) properties["platform"] = "Unknown"; - if (!properties.contains("copyright")) properties["copyright"] = "Copyright 2015 - 2018 Copernica BV"; - if (!properties.contains("information")) properties["information"] = "https://www.copernica.com"; + if (!properties.contains("version")) properties["version"] = "AMQP-CPP " VERSION_NAME; + 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; - + +#if defined(_WIN32) || defined(_WIN64) + // i don't know that much about win32, so let's use hardcoded string + if (!properties.contains("product")) properties["product"] = "application based on AMQP-CPP"; + if (!properties.contains("platform")) properties["platform"] = "windows"; +#else + // on unix-like systems I know how to retrieve application and platform info + if (!properties.contains("product")) properties["product"] = ProgramName(); + if (!properties.contains("platform")) properties["platform"] = PlatformName(); +#endif + // send back a connection start ok frame connection->send(ConnectionStartOKFrame(properties, "PLAIN", connection->login().saslPlain(), "en_US")); // done return true; } + }; /** diff --git a/src/platformname.h b/src/platformname.h new file mode 100644 index 0000000..a1bccf2 --- /dev/null +++ b/src/platformname.h @@ -0,0 +1,69 @@ +/** + * PlatformName.h + * + * Class to extract the platform name (operating system, etc) + * + * @author Emiel Bruijntjes + * @copyright 2023 Copernica BV + */ + +/** + * Include guard + */ +#pragma once + +/** + * Dependencies + */ +#include + +/** + * Begin of namespace + */ +namespace AMQP { + +/** + * Class definition + */ +class PlatformName +{ +private: + /** + * The string holding all info + * @var std::string + */ + std::string _value; + +public: + /** + * Constructor + */ + PlatformName() + { + // all information + struct utsname info; + + // retrieve system info + if (uname(&info) != 0) return; + + // add all info + _value.append(info.sysname).append(" ").append(info.nodename).append(" ").append(info.release).append(" ").append(info.version); + } + + /** + * Destructor + */ + virtual ~PlatformName() = default; + + /** + * Cast to a const char * + * @return const char * + */ + operator const char * () const { return _value.data(); } +}; + +/** + * End of namespace + */ +} + diff --git a/src/programname.h b/src/programname.h new file mode 100644 index 0000000..4a16c35 --- /dev/null +++ b/src/programname.h @@ -0,0 +1,82 @@ +/** + * ProgramName.h + * + * Helper class that detects the name of the program + * + * @author Emiel Bruijntjes + * @copyright 2023 Copernica BV + */ + +/** + * Include guard + */ +#pragma once + +/** + * Dependencies + */ +#include +#include + +/** + * Begin of namespace + */ +namespace AMQP { + +/** + * Class definition + */ +class ProgramName +{ +private: + /** + * Path of the program + * @var char[] + */ + char _path[PATH_MAX]; + + /** + * Is the _path valid? + * @var bool + */ + bool _valid; + +public: + /** + * Constructor + */ + ProgramName() + { + // read the link target + auto size = readlink("/proc/self/exe", _path, PATH_MAX); + + // -1 is returned on error, otherwise the size + _valid = size >= 0; + + // set trailing null byte + _path[size == PATH_MAX ? PATH_MAX-1 : size] = '\0'; + } + + /** + * Destructor + */ + virtual ~ProgramName() = default; + + /** + * Cast to a const char * + * @return const char * + */ + operator const char * () const + { + // empty string when not valid + if (!_valid) return ""; + + // return path to executable + return _path; + } +}; + +/** + * End of namespace + */ +}