diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index 213297c..6982bb4 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -430,6 +430,7 @@ rule select-platform-specific-sources ( properties * ) if ! [ has-config-flag BOOST_LOG_WITHOUT_IPC : $(properties) ] { + result += windows/object_name.cpp ; result += windows/mapped_shared_memory.cpp ; result += windows/ipc_sync_wrappers.cpp ; result += windows/ipc_reliable_message_queue.cpp ; @@ -456,6 +457,7 @@ rule select-platform-specific-sources ( properties * ) if ! [ has-config-flag BOOST_LOG_WITHOUT_IPC : $(properties) ] { + result += posix/object_name.cpp ; result += posix/ipc_reliable_message_queue.cpp ; } } diff --git a/example/doc/sinks_ipc_logger.cpp b/example/doc/sinks_ipc_logger.cpp index 9a234e3..f5adeb2 100644 --- a/example/doc/sinks_ipc_logger.cpp +++ b/example/doc/sinks_ipc_logger.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -47,7 +48,7 @@ int main() // named "ipc_message_queue". boost::shared_ptr< sink_t > sink = boost::make_shared< sink_t > ( - keywords::name = "ipc_message_queue", + keywords::name = logging::ipc::object_name(logging::ipc::object_name::user, "ipc_message_queue"), keywords::open_mode = logging::open_mode::open_or_create, keywords::capacity = 256, keywords::block_size = 1024, diff --git a/example/doc/sinks_ipc_viewer.cpp b/example/doc/sinks_ipc_viewer.cpp index 02cdba4..21a651c 100644 --- a/example/doc/sinks_ipc_viewer.cpp +++ b/example/doc/sinks_ipc_viewer.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include namespace logging = boost::log; @@ -26,7 +27,7 @@ int main() // message queue named "ipc_message_queue". queue_t queue ( - keywords::name = "ipc_message_queue", + keywords::name = logging::ipc::object_name(logging::ipc::object_name::user, "ipc_message_queue"), keywords::open_mode = logging::open_mode::open_or_create, keywords::capacity = 256, keywords::block_size = 1024, diff --git a/include/boost/log/support/exception.hpp b/include/boost/log/support/exception.hpp index d1afae0..160521d 100644 --- a/include/boost/log/support/exception.hpp +++ b/include/boost/log/support/exception.hpp @@ -64,10 +64,16 @@ inline current_scope_info current_scope() return current_scope_info(attributes::named_scope::get_scopes()); } +namespace ipc { + +class object_name; + /*! * System resource name */ -typedef error_info< struct resource_name_tag, std::string > resource_name_info; +typedef error_info< struct object_name_tag, object_name > object_name_info; + +} // namespace ipc BOOST_LOG_CLOSE_NAMESPACE // namespace log diff --git a/include/boost/log/utility/ipc/object_name.hpp b/include/boost/log/utility/ipc/object_name.hpp new file mode 100644 index 0000000..582ecdc --- /dev/null +++ b/include/boost/log/utility/ipc/object_name.hpp @@ -0,0 +1,271 @@ +/* + * Copyright Andrey Semashev 2016. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ +/*! + * \file utility/ipc/object_name.hpp + * \author Andrey Semashev + * \date 05.03.2016 + * + * The header contains declaration of a system object name wrapper. + */ + +#ifndef BOOST_LOG_UTILITY_IPC_OBJECT_NAME_HPP_INCLUDED_ +#define BOOST_LOG_UTILITY_IPC_OBJECT_NAME_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { + +BOOST_LOG_OPEN_NAMESPACE + +namespace ipc { + +/*! + * \brief A system object name class + * + * In order to identify a system-wide object such as a shared memory segment or a named synchronization primitive the object has to be given a name. + * The format of the name is specific to the operating system and the \c object_name class provides an abstraction for names of objects. It also + * provides means for scoping, which allows to avoid name clashes between different processes. + * + * The object name is a UTF-8 encoded string. The portable object name should consist of the following characters: + * + *
+ * A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
+ * a b c d e f g h i j k l m n o p q r s t u v w x y z
+ * 0 1 2 3 4 5 6 7 8 9 . _ -
+ * 
+ * + * \note The character set corresponds to the POSIX Portable Filename Character Set (http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_278). + * + * Use of other characters may result in non-portable system-specific behavior. + * + * The name can have one of the following scopes: + * + * \li \c global - objects within this scope are visible to any process on the system. In order to use this scope the process may need to have + * extended privileges. This scope is not available for Windows Store applications. + * \li \c user - objects within this scope can be opened by processes running under the same user as the current process. + * \li \c session - objects within this scope are visible to processes within the session of the current process. The definition of a session may vary between + * operating systems. On POSIX, a session is typically a group of processes attached to a single virtual terminal device. On Windows a session is + * started when a user logs into the system. There is also a separate session for Windows services. + * \li \c process_group - objects within this scope are visible to processes within the process group of the current process. Currently, on Windows all processes + * running in the current session are considered members of the same process group. This may change in future. + * + * The scopes are not overlapping. For instance, if an object is created in the global scope, the object cannot be opened with the same name but in user's scope. + * + * Note that name scoping is not a security feature. On some systems any process on the system has technical capability to open objects within any scope. + * The scope is only used to help avoid name clashes between processes using \c object_name to identify objects. + */ +class object_name +{ +public: + //! Name scopes + enum scope + { + global, //!< The name has global scope; any process in the system has the potential to open the resource identified by the name + user, //!< The name is limited to processes running under the current user + session, //!< The name is limited to processes running in the current login session + process_group //!< The name is limited to processes running in the current process group + }; + +#if !defined(BOOST_LOG_DOXYGEN_PASS) + + BOOST_COPYABLE_AND_MOVABLE(object_name) + +private: + std::string m_name; + +#endif // !defined(BOOST_LOG_DOXYGEN_PASS) + +public: + /*! + * Default constructor. The method creates an empty object name. + * + * \post empty() == true + */ + object_name() BOOST_NOEXCEPT + { + } + + /*! + * Move constructor. + */ + object_name(BOOST_RV_REF(object_name) that) BOOST_NOEXCEPT + { + m_name.swap(that.m_name); + } + + /*! + * Copy constructor. + */ + object_name(object_name const& that) : m_name(that.m_name) + { + } + + /*! + * Constructor from the native string. + * + * \param str The object name string, must not be \c NULL. The string format is specific to the operating system. + */ + static object_name from_native(const char* str) + { + object_name name; + name.m_name = str; + return name; + } + + /*! + * Constructor from the native string. + * + * \param str The object name string. The string format is specific to the operating system. + */ + static object_name from_native(std::string const& str) + { + object_name name; + name.m_name = str; + return name; + } + + /*! + * Constructor from the object name + * \param ns The scope of the object name + * \param str The object name, must not be NULL. + */ + BOOST_LOG_API object_name(scope ns, const char* str); + + /*! + * Constructor from the object name + * \param ns The scope of the object name + * \param str The object name + */ + BOOST_LOG_API object_name(scope ns, std::string const& str); + + /*! + * Move assignment + */ + object_name& operator= (BOOST_RV_REF(object_name) that) BOOST_NOEXCEPT + { + m_name.clear(); + m_name.swap(that.m_name); + return *this; + } + + /*! + * Copy assignment + */ + object_name& operator= (BOOST_COPY_ASSIGN_REF(object_name) that) + { + m_name = that.m_name; + return *this; + } + + /*! + * Returns \c true if the object name is empty + */ + bool empty() const BOOST_NOEXCEPT { return m_name.empty(); } + + /*! + * Returns length of the name, in bytes + */ + std::size_t size() const BOOST_NOEXCEPT { return m_name.size(); } + + /*! + * Returns the name string + */ + const char* c_str() const BOOST_NOEXCEPT { return m_name.c_str(); } + + /*! + * Swaps the object name with another object name + */ + void swap(object_name& that) BOOST_NOEXCEPT { m_name.swap(that.m_name); } + + /*! + * Swaps two object names + */ + friend void swap(object_name& left, object_name& right) BOOST_NOEXCEPT + { + left.swap(right); + } + + /*! + * Returns string representation of the object name + */ + friend std::string to_string(object_name const& name) + { + return name.m_name; + } + + /*! + * Equality operator + */ + friend bool operator== (object_name const& left, object_name const& right) BOOST_NOEXCEPT + { + return left.m_name == right.m_name; + } + /*! + * Inequality operator + */ + friend bool operator!= (object_name const& left, object_name const& right) BOOST_NOEXCEPT + { + return left.m_name != right.m_name; + } + /*! + * Less operator + */ + friend bool operator< (object_name const& left, object_name const& right) BOOST_NOEXCEPT + { + return left.m_name < right.m_name; + } + /*! + * Greater operator + */ + friend bool operator> (object_name const& left, object_name const& right) BOOST_NOEXCEPT + { + return left.m_name > right.m_name; + } + /*! + * Less or equal operator + */ + friend bool operator<= (object_name const& left, object_name const& right) BOOST_NOEXCEPT + { + return left.m_name <= right.m_name; + } + /*! + * Greater or equal operator + */ + friend bool operator>= (object_name const& left, object_name const& right) BOOST_NOEXCEPT + { + return left.m_name >= right.m_name; + } + + /*! + * Stream ouput operator + */ + template< typename CharT, typename TraitsT > + friend std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, object_name const& name) + { + strm << name.c_str(); + return strm; + } +}; + +} // namespace ipc + +BOOST_LOG_CLOSE_NAMESPACE // namespace log + +} // namespace boost + +#include + +#endif // BOOST_LOG_UTILITY_IPC_OBJECT_NAME_HPP_INCLUDED_ diff --git a/include/boost/log/utility/ipc/reliable_message_queue.hpp b/include/boost/log/utility/ipc/reliable_message_queue.hpp index 77bd30b..0a6abe8 100644 --- a/include/boost/log/utility/ipc/reliable_message_queue.hpp +++ b/include/boost/log/utility/ipc/reliable_message_queue.hpp @@ -29,8 +29,8 @@ #include #include #include +#include #include -#include #include #ifdef BOOST_HAS_PRAGMA_ONCE @@ -63,13 +63,8 @@ struct enable_if_byte< unsigned char, R > { typedef R type; }; * The format of the messages is user-defined and must be consistent across all writers and the reader. The queue does * not enforce any specific format of the messages, other than they should be supplied as a contiguous array of bytes. * - * The queue internally uses a process-shared storage identified by a string (the queue name). The contents of the string are - * specific to the target OS. For best portability the following guidelines should be followed: - * - * \li On POSIX systems the string should start with a forward slash ('/') and contain no other slashes. - * \li On Windows the string must be encoded in UTF-8. In case if the queue is used for communication between processes - * running in different sessions, the string must start with the "Global\" prefix. Other than that prefix, the - * string should not contain slashes. + * The queue internally uses a process-shared storage identified by an \c object_name (the queue name). Refer to \c object_name + * documentation for details on restrictions imposed on object names. * * The queue storage is organized as a fixed number of blocks of a fixed size. The block size must be an integer power of 2 and * is expressed in bytes. Each written message, together with some metadata added by the queue, consumes an integer number @@ -161,7 +156,7 @@ public: reliable_message_queue ( open_mode::create_only_tag, - const char* name, + object_name const& name, uint32_t capacity, uint32_t block_size, overflow_policy oflow_policy = block_on_overflow, @@ -190,7 +185,7 @@ public: reliable_message_queue ( open_mode::open_or_create_tag, - const char* name, + object_name const& name, uint32_t capacity, uint32_t block_size, overflow_policy oflow_policy = block_on_overflow, @@ -217,7 +212,7 @@ public: reliable_message_queue ( open_mode::open_only_tag, - const char* name, + object_name const& name, overflow_policy oflow_policy = block_on_overflow, permissions const& perms = permissions() ) : @@ -321,7 +316,7 @@ public: */ BOOST_LOG_API void create ( - const char* name, + object_name const& name, uint32_t capacity, uint32_t block_size, overflow_policy oflow_policy = block_on_overflow, @@ -346,7 +341,7 @@ public: */ BOOST_LOG_API void open_or_create ( - const char* name, + object_name const& name, uint32_t capacity, uint32_t block_size, overflow_policy oflow_policy = block_on_overflow, @@ -369,7 +364,7 @@ public: */ BOOST_LOG_API void open ( - const char* name, + object_name const& name, overflow_policy oflow_policy = block_on_overflow, permissions const& perms = permissions() ); @@ -399,7 +394,7 @@ public: * * \return Name of the associated message queue */ - BOOST_LOG_API const char* name() const; + BOOST_LOG_API object_name const& name() const; /*! * The method returns the maximum number of allocation blocks the associated message queue @@ -703,12 +698,9 @@ public: * places to ensure compatibility with other platforms and future library versions, which may change implementation * of the queue. * - * \param name Name of the message queue to be associated with. A valid name is one - * that can be used as a C++ identifier or is a keyword. - * On Windows platforms, the name is used to compose kernel object names, - * and you may need to add the "Global\" prefix to the name in certain cases. + * \param name Name of the message queue to be removed. */ - static BOOST_LOG_API void remove(const char* name); + static BOOST_LOG_API void remove(object_name const& name); #if !defined(BOOST_LOG_DOXYGEN_PASS) private: @@ -724,21 +716,21 @@ private: template< typename ArgsT > void construct_dispatch(open_mode::create_only_tag, ArgsT const& args) { - this->create(boost::log::aux::c_str(args[keywords::name]), args[keywords::capacity], args[keywords::block_size], args[keywords::overflow_policy | block_on_overflow], args[keywords::permissions | permissions()]); + this->create(args[keywords::name], args[keywords::capacity], args[keywords::block_size], args[keywords::overflow_policy | block_on_overflow], args[keywords::permissions | permissions()]); } //! Implementation of the constructor with named arguments template< typename ArgsT > void construct_dispatch(open_mode::open_or_create_tag, ArgsT const& args) { - this->open_or_create(boost::log::aux::c_str(args[keywords::name]), args[keywords::capacity], args[keywords::block_size], args[keywords::overflow_policy | block_on_overflow], args[keywords::permissions | permissions()]); + this->open_or_create(args[keywords::name], args[keywords::capacity], args[keywords::block_size], args[keywords::overflow_policy | block_on_overflow], args[keywords::permissions | permissions()]); } //! Implementation of the constructor with named arguments template< typename ArgsT > void construct_dispatch(open_mode::open_only_tag, ArgsT const& args) { - this->open(boost::log::aux::c_str(args[keywords::name]), args[keywords::overflow_policy | block_on_overflow], args[keywords::permissions | permissions()]); + this->open(args[keywords::name], args[keywords::overflow_policy | block_on_overflow], args[keywords::permissions | permissions()]); } //! Closes the message queue, if it's open diff --git a/src/code_conversion.cpp b/src/code_conversion.cpp index 13df238..03f5d72 100644 --- a/src/code_conversion.cpp +++ b/src/code_conversion.cpp @@ -213,7 +213,7 @@ std::wstring utf8_to_utf16(const char* str) if (utf8_len == 0) return std::wstring(); else if (BOOST_UNLIKELY(utf8_len > static_cast< std::size_t >((std::numeric_limits< int >::max)()))) - BOOST_LOG_THROW_DESCR(bad_alloc, "Multibyte string too long"); + BOOST_LOG_THROW_DESCR(bad_alloc, "UTF-8 string too long"); int len = boost::detail::winapi::MultiByteToWideChar(boost::detail::winapi::CP_UTF8_, boost::detail::winapi::MB_ERR_INVALID_CHARS_, str, static_cast< int >(utf8_len), NULL, 0); if (BOOST_LIKELY(len > 0)) @@ -232,6 +232,32 @@ std::wstring utf8_to_utf16(const char* str) BOOST_LOG_UNREACHABLE_RETURN(std::wstring()); } +//! Converts UTF-16 to UTF-8 +std::string utf16_to_utf8(const wchar_t* wstr) +{ + std::size_t utf16_len = std::wcslen(wstr); + if (utf16_len == 0) + return std::string(); + else if (BOOST_UNLIKELY(utf16_len > static_cast< std::size_t >((std::numeric_limits< int >::max)()))) + BOOST_LOG_THROW_DESCR(bad_alloc, "UTF-16 string too long"); + + int len = boost::detail::winapi::WideCharToMultiByte(boost::detail::winapi::CP_UTF8_, boost::detail::winapi::MB_ERR_INVALID_CHARS_, wstr, static_cast< int >(utf16_len), NULL, 0, NULL, NULL); + if (BOOST_LIKELY(len > 0)) + { + std::string str; + str.resize(len); + + len = boost::detail::winapi::WideCharToMultiByte(boost::detail::winapi::CP_UTF8_, boost::detail::winapi::MB_ERR_INVALID_CHARS_, wstr, static_cast< int >(utf16_len), &str[0], len, NULL, NULL); + if (BOOST_LIKELY(len > 0)) + { + return str; + } + } + + BOOST_LOG_THROW_DESCR(conversion_error, "Failed to convert UTF-16 to UTF-8"); + BOOST_LOG_UNREACHABLE_RETURN(std::string()); +} + #endif // defined(BOOST_WINDOWS) } // namespace aux diff --git a/src/posix/ipc_reliable_message_queue.cpp b/src/posix/ipc_reliable_message_queue.cpp index 01285c2..7cdafcf 100644 --- a/src/posix/ipc_reliable_message_queue.cpp +++ b/src/posix/ipc_reliable_message_queue.cpp @@ -201,23 +201,27 @@ private: //! The flag indicates that stop has been requested bool m_stop; + //! Queue shared memory object name + const object_name m_name; + public: //! The constructor creates a new shared memory segment implementation ( open_mode::create_only_tag, - char const* name, + object_name const& name, uint32_t capacity, uint32_t block_size, overflow_policy oflow_policy, permissions const& perms ) : - m_shared_memory(boost::interprocess::create_only, name, boost::interprocess::read_write, boost::interprocess::permissions(perms.get_native())), + m_shared_memory(boost::interprocess::create_only, name.c_str(), boost::interprocess::read_write, boost::interprocess::permissions(perms.get_native())), m_region(), m_overflow_policy(oflow_policy), m_block_size_mask(0u), m_block_size_log2(0u), - m_stop(false) + m_stop(false), + m_name(name) { create_region(capacity, block_size); } @@ -226,18 +230,19 @@ public: implementation ( open_mode::open_or_create_tag, - char const* name, + object_name const& name, uint32_t capacity, uint32_t block_size, overflow_policy oflow_policy, permissions const& perms ) : - m_shared_memory(boost::interprocess::open_or_create, name, boost::interprocess::read_write, boost::interprocess::permissions(perms.get_native())), + m_shared_memory(boost::interprocess::open_or_create, name.c_str(), boost::interprocess::read_write, boost::interprocess::permissions(perms.get_native())), m_region(), m_overflow_policy(oflow_policy), m_block_size_mask(0u), m_block_size_log2(0u), - m_stop(false) + m_stop(false), + m_name(name) { boost::interprocess::offset_t shmem_size = 0; if (!m_shared_memory.get_size(shmem_size) || shmem_size == 0) @@ -250,15 +255,16 @@ public: implementation ( open_mode::open_only_tag, - char const* name, + object_name const& name, overflow_policy oflow_policy ) : - m_shared_memory(boost::interprocess::open_only, name, boost::interprocess::read_write), + m_shared_memory(boost::interprocess::open_only, name.c_str(), boost::interprocess::read_write), m_region(), m_overflow_policy(oflow_policy), m_block_size_mask(0u), m_block_size_log2(0u), - m_stop(false) + m_stop(false), + m_name(name) { boost::interprocess::offset_t shmem_size = 0; if (!m_shared_memory.get_size(shmem_size)) @@ -272,9 +278,9 @@ public: close_region(); } - const char* name() const BOOST_NOEXCEPT + object_name const& name() const BOOST_NOEXCEPT { - return m_shared_memory.get_name(); + return m_name; } uint32_t capacity() const BOOST_NOEXCEPT @@ -666,7 +672,7 @@ private: } }; -BOOST_LOG_API void reliable_message_queue::create(const char* name, uint32_t capacity, uint32_t block_size, overflow_policy oflow_policy, permissions const& perms) +BOOST_LOG_API void reliable_message_queue::create(object_name const& name, uint32_t capacity, uint32_t block_size, overflow_policy oflow_policy, permissions const& perms) { BOOST_ASSERT(m_impl == NULL); if (!boost::log::aux::is_power_of_2(block_size)) @@ -677,16 +683,16 @@ BOOST_LOG_API void reliable_message_queue::create(const char* name, uint32_t cap } catch (boost::exception& e) { - e << boost::log::resource_name_info(name); + e << boost::log::ipc::object_name_info(name); throw; } catch (boost::interprocess::interprocess_exception& e) { - BOOST_THROW_EXCEPTION(boost::enable_error_info(system_error(boost::system::error_code(e.get_native_error(), boost::system::system_category()), e.what())) << boost::log::resource_name_info(name)); + BOOST_THROW_EXCEPTION(boost::enable_error_info(system_error(boost::system::error_code(e.get_native_error(), boost::system::system_category()), e.what())) << boost::log::ipc::object_name_info(name)); } } -BOOST_LOG_API void reliable_message_queue::open_or_create(const char* name, uint32_t capacity, uint32_t block_size, overflow_policy oflow_policy, permissions const& perms) +BOOST_LOG_API void reliable_message_queue::open_or_create(object_name const& name, uint32_t capacity, uint32_t block_size, overflow_policy oflow_policy, permissions const& perms) { BOOST_ASSERT(m_impl == NULL); if (!boost::log::aux::is_power_of_2(block_size)) @@ -697,16 +703,16 @@ BOOST_LOG_API void reliable_message_queue::open_or_create(const char* name, uint } catch (boost::exception& e) { - e << boost::log::resource_name_info(name); + e << boost::log::ipc::object_name_info(name); throw; } catch (boost::interprocess::interprocess_exception& e) { - BOOST_THROW_EXCEPTION(boost::enable_error_info(system_error(boost::system::error_code(e.get_native_error(), boost::system::system_category()), e.what())) << boost::log::resource_name_info(name)); + BOOST_THROW_EXCEPTION(boost::enable_error_info(system_error(boost::system::error_code(e.get_native_error(), boost::system::system_category()), e.what())) << boost::log::ipc::object_name_info(name)); } } -BOOST_LOG_API void reliable_message_queue::open(char const* name, overflow_policy oflow_policy, permissions const&) +BOOST_LOG_API void reliable_message_queue::open(object_name const& name, overflow_policy oflow_policy, permissions const&) { BOOST_ASSERT(m_impl == NULL); try @@ -715,12 +721,12 @@ BOOST_LOG_API void reliable_message_queue::open(char const* name, overflow_polic } catch (boost::exception& e) { - e << boost::log::resource_name_info(name); + e << boost::log::ipc::object_name_info(name); throw; } catch (boost::interprocess::interprocess_exception& e) { - BOOST_THROW_EXCEPTION(boost::enable_error_info(system_error(boost::system::error_code(e.get_native_error(), boost::system::system_category()), e.what())) << boost::log::resource_name_info(name)); + BOOST_THROW_EXCEPTION(boost::enable_error_info(system_error(boost::system::error_code(e.get_native_error(), boost::system::system_category()), e.what())) << boost::log::ipc::object_name_info(name)); } } @@ -733,12 +739,12 @@ BOOST_LOG_API void reliable_message_queue::clear() } catch (boost::exception& e) { - e << boost::log::resource_name_info(m_impl->name()); + e << boost::log::ipc::object_name_info(m_impl->name()); throw; } } -BOOST_LOG_API const char* reliable_message_queue::name() const +BOOST_LOG_API object_name const& reliable_message_queue::name() const { BOOST_ASSERT(m_impl != NULL); return m_impl->name(); @@ -765,7 +771,7 @@ BOOST_LOG_API void reliable_message_queue::stop_local() } catch (boost::exception& e) { - e << boost::log::resource_name_info(m_impl->name()); + e << boost::log::ipc::object_name_info(m_impl->name()); throw; } } @@ -779,7 +785,7 @@ BOOST_LOG_API void reliable_message_queue::reset_local() } catch (boost::exception& e) { - e << boost::log::resource_name_info(m_impl->name()); + e << boost::log::ipc::object_name_info(m_impl->name()); throw; } } @@ -799,7 +805,7 @@ BOOST_LOG_API reliable_message_queue::operation_result reliable_message_queue::s } catch (boost::exception& e) { - e << boost::log::resource_name_info(m_impl->name()); + e << boost::log::ipc::object_name_info(m_impl->name()); throw; } } @@ -813,7 +819,7 @@ BOOST_LOG_API bool reliable_message_queue::try_send(void const* message_data, ui } catch (boost::exception& e) { - e << boost::log::resource_name_info(m_impl->name()); + e << boost::log::ipc::object_name_info(m_impl->name()); throw; } } @@ -827,7 +833,7 @@ BOOST_LOG_API reliable_message_queue::operation_result reliable_message_queue::d } catch (boost::exception& e) { - e << boost::log::resource_name_info(m_impl->name()); + e << boost::log::ipc::object_name_info(m_impl->name()); throw; } } @@ -841,7 +847,7 @@ BOOST_LOG_API bool reliable_message_queue::do_try_receive(receive_handler handle } catch (boost::exception& e) { - e << boost::log::resource_name_info(m_impl->name()); + e << boost::log::ipc::object_name_info(m_impl->name()); throw; } } @@ -858,9 +864,9 @@ BOOST_LOG_API void reliable_message_queue::fixed_buffer_receive_handler(void* st p->size -= size; } -BOOST_LOG_API void reliable_message_queue::remove(const char* name) +BOOST_LOG_API void reliable_message_queue::remove(object_name const& name) { - boost::interprocess::shared_memory_object::remove(name); + boost::interprocess::shared_memory_object::remove(name.c_str()); } } // namespace ipc diff --git a/src/posix/object_name.cpp b/src/posix/object_name.cpp new file mode 100644 index 0000000..0d2de72 --- /dev/null +++ b/src/posix/object_name.cpp @@ -0,0 +1,143 @@ +/* + * Copyright Andrey Semashev 2016. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ +/*! + * \file posix/object_name.cpp + * \author Andrey Semashev + * \date 06.03.2016 + * + * \brief This header is the Boost.Log library implementation, see the library documentation + * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace karma = boost::spirit::karma; + +namespace boost { + +BOOST_LOG_OPEN_NAMESPACE + +namespace ipc { + +BOOST_LOG_ANONYMOUS_NAMESPACE { + +//! Formats an integer identifier into the string +template< typename Identifier > +inline void format_id(Identifier id, std::string& str) +{ + // Note: in the code below, avoid involving locale for string formatting to make sure the names are as stable as possible + typedef typename boost::make_unsigned< Identifier >::type unsigned_id_t; + char buf[std::numeric_limits< unsigned_id_t >::digits10 + 2]; + char* p = buf; + + typedef karma::uint_generator< unsigned_id_t, 10 > unsigned_id_gen; + karma::generate(p, unsigned_id_gen(), static_cast< unsigned_id_t >(id)); + str.append(buf, p); +} + +//! Returns a prefix string for a shared resource according to the scope +std::string get_scope_prefix(object_name::scope ns) +{ + std::string prefix = "/boost.log."; + switch (ns) + { + case object_name::process_group: + { + prefix.append("pgid."); + format_id(getpgrp(), prefix); + } + break; + + case object_name::session: + { + prefix.append("sid."); + format_id(getsid(0), prefix); + } + break; + + case object_name::user: + { + const uid_t uid = getuid(); + + long limit = sysconf(_SC_GETPW_R_SIZE_MAX); + if (limit <= 0) + limit = 65536; + std::vector< char > string_storage; + string_storage.resize(static_cast< std::size_t >(limit)); + passwd pwd = {}, *result = NULL; + + try + { + const int err = getpwuid_r(uid, &pwd, &string_storage[0], string_storage.size(), &result); + if (err == 0 && result && result->pw_name) + { + prefix += "user."; + prefix += result->pw_name; + } + else + { + prefix += "uid."; + format_id(uid, prefix); + } + + // Avoid leaving sensitive data in memory, if there is any + std::memset(&pwd, 0, sizeof(pwd)); + std::memset(&string_storage[0], 0, string_storage.size()); + } + catch (...) + { + std::memset(&pwd, 0, sizeof(pwd)); + std::memset(&string_storage[0], 0, string_storage.size()); + throw; + } + } + break; + + default: + prefix += "global"; + break; + } + + prefix.push_back('.'); + + return boost::move(prefix); +} + +} // namespace + +//! Constructor from the object name +BOOST_LOG_API object_name::object_name(scope ns, const char* str) : + m_name(get_scope_prefix(ns) + str) +{ +} + +//! Constructor from the object name +BOOST_LOG_API object_name::object_name(scope ns, std::string const& str) : + m_name(get_scope_prefix(ns) + str) +{ +} + +} // namespace ipc + +BOOST_LOG_CLOSE_NAMESPACE // namespace log + +} // namespace boost + +#include diff --git a/src/windows/auto_handle.hpp b/src/windows/auto_handle.hpp new file mode 100644 index 0000000..158f9bd --- /dev/null +++ b/src/windows/auto_handle.hpp @@ -0,0 +1,79 @@ +/* + * Copyright Andrey Semashev 2016. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ +/*! + * \file windows/auto_handle.hpp + * \author Andrey Semashev + * \date 07.03.2016 + * + * \brief This header is the Boost.Log library implementation, see the library documentation + * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html. + */ + +#ifndef BOOST_LOG_WINDOWS_AUTO_HANDLE_HPP_INCLUDED_ +#define BOOST_LOG_WINDOWS_AUTO_HANDLE_HPP_INCLUDED_ + +#include +#include +#include +#include + +namespace boost { + +BOOST_LOG_OPEN_NAMESPACE + +namespace ipc { + +namespace aux { + +//! A wrapper around a kernel object handle. Automatically closes the handle on destruction. +class auto_handle +{ +private: + boost::detail::winapi::HANDLE_ m_handle; + +public: + explicit auto_handle(boost::detail::winapi::HANDLE_ h = NULL) BOOST_NOEXCEPT : m_handle(h) + { + } + + ~auto_handle() BOOST_NOEXCEPT + { + if (m_handle) + BOOST_VERIFY(boost::detail::winapi::CloseHandle(m_handle) != 0); + } + + void init(boost::detail::winapi::HANDLE_ h) BOOST_NOEXCEPT + { + BOOST_ASSERT(m_handle == NULL); + m_handle = h; + } + + boost::detail::winapi::HANDLE_ get() const BOOST_NOEXCEPT { return m_handle; } + boost::detail::winapi::HANDLE_* get_ptr() const BOOST_NOEXCEPT { return &m_handle; } + + void swap(auto_handle& that) BOOST_NOEXCEPT + { + boost::detail::winapi::HANDLE_ h = m_handle; + m_handle = that.m_handle; + that.m_handle = h; + } + + BOOST_DELETED_FUNCTION(auto_handle(auto_handle const&)) + BOOST_DELETED_FUNCTION(auto_handle& operator=(auto_handle const&)) +}; + +} // namespace aux + +} // namespace ipc + +BOOST_LOG_CLOSE_NAMESPACE // namespace log + +} // namespace boost + +#include + +#endif // BOOST_LOG_WINDOWS_AUTO_HANDLE_HPP_INCLUDED_ diff --git a/src/windows/ipc_reliable_message_queue.cpp b/src/windows/ipc_reliable_message_queue.cpp index cf9d04a..9d83a9c 100644 --- a/src/windows/ipc_reliable_message_queue.cpp +++ b/src/windows/ipc_reliable_message_queue.cpp @@ -198,14 +198,14 @@ private: boost::log::ipc::aux::auto_handle m_stop; //! The queue name, as specified by the user - const std::string m_name; + const object_name m_name; public: //! The constructor creates a new shared memory segment implementation ( open_mode::create_only_tag, - const char* name, + object_name const& name, uint32_t capacity, uint32_t block_size, overflow_policy oflow_policy, @@ -216,7 +216,7 @@ public: m_block_size_log2(0u), m_name(name) { - const std::wstring wname = boost::log::aux::utf8_to_utf16(name); + const std::wstring wname = boost::log::aux::utf8_to_utf16(name.c_str()); const std::size_t shmem_size = estimate_region_size(capacity, block_size); m_shared_memory.create(wname.c_str(), shmem_size, perms); m_shared_memory.map(); @@ -228,7 +228,7 @@ public: implementation ( open_mode::open_or_create_tag, - const char* name, + object_name const& name, uint32_t capacity, uint32_t block_size, overflow_policy oflow_policy, @@ -239,7 +239,7 @@ public: m_block_size_log2(0u), m_name(name) { - const std::wstring wname = boost::log::aux::utf8_to_utf16(name); + const std::wstring wname = boost::log::aux::utf8_to_utf16(name.c_str()); const std::size_t shmem_size = estimate_region_size(capacity, block_size); const bool created = m_shared_memory.create_or_open(wname.c_str(), shmem_size, perms); m_shared_memory.map(); @@ -254,7 +254,7 @@ public: implementation ( open_mode::open_only_tag, - const char* name, + object_name const& name, overflow_policy oflow_policy, permissions const& perms ) : @@ -263,14 +263,14 @@ public: m_block_size_log2(0u), m_name(name) { - const std::wstring wname = boost::log::aux::utf8_to_utf16(name); + const std::wstring wname = boost::log::aux::utf8_to_utf16(name.c_str()); m_shared_memory.open(wname.c_str()); m_shared_memory.map(); adopt_queue(wname, m_shared_memory.size(), perms); } - std::string const& name() const BOOST_NOEXCEPT + object_name const& name() const BOOST_NOEXCEPT { return m_name; } @@ -621,7 +621,7 @@ private: } }; -BOOST_LOG_API void reliable_message_queue::create(const char* name, uint32_t capacity, uint32_t block_size, overflow_policy oflow_policy, permissions const& perms) +BOOST_LOG_API void reliable_message_queue::create(object_name const& name, uint32_t capacity, uint32_t block_size, overflow_policy oflow_policy, permissions const& perms) { BOOST_ASSERT(m_impl == NULL); if (!boost::log::aux::is_power_of_2(block_size)) @@ -632,12 +632,12 @@ BOOST_LOG_API void reliable_message_queue::create(const char* name, uint32_t cap } catch (boost::exception& e) { - e << boost::log::resource_name_info(name); + e << boost::log::ipc::object_name_info(name); throw; } } -BOOST_LOG_API void reliable_message_queue::open_or_create(const char* name, uint32_t capacity, uint32_t block_size, overflow_policy oflow_policy, permissions const& perms) +BOOST_LOG_API void reliable_message_queue::open_or_create(object_name const& name, uint32_t capacity, uint32_t block_size, overflow_policy oflow_policy, permissions const& perms) { BOOST_ASSERT(m_impl == NULL); if (!boost::log::aux::is_power_of_2(block_size)) @@ -648,12 +648,12 @@ BOOST_LOG_API void reliable_message_queue::open_or_create(const char* name, uint } catch (boost::exception& e) { - e << boost::log::resource_name_info(name); + e << boost::log::ipc::object_name_info(name); throw; } } -BOOST_LOG_API void reliable_message_queue::open(char const* name, overflow_policy oflow_policy, permissions const& perms) +BOOST_LOG_API void reliable_message_queue::open(object_name const& name, overflow_policy oflow_policy, permissions const& perms) { BOOST_ASSERT(m_impl == NULL); try @@ -662,7 +662,7 @@ BOOST_LOG_API void reliable_message_queue::open(char const* name, overflow_polic } catch (boost::exception& e) { - e << boost::log::resource_name_info(name); + e << boost::log::ipc::object_name_info(name); throw; } } @@ -676,15 +676,15 @@ BOOST_LOG_API void reliable_message_queue::clear() } catch (boost::exception& e) { - e << boost::log::resource_name_info(m_impl->name()); + e << boost::log::ipc::object_name_info(m_impl->name()); throw; } } -BOOST_LOG_API const char* reliable_message_queue::name() const +BOOST_LOG_API object_name const& reliable_message_queue::name() const { BOOST_ASSERT(m_impl != NULL); - return m_impl->name().c_str(); + return m_impl->name(); } BOOST_LOG_API uint32_t reliable_message_queue::capacity() const @@ -708,7 +708,7 @@ BOOST_LOG_API void reliable_message_queue::stop_local() } catch (boost::exception& e) { - e << boost::log::resource_name_info(m_impl->name()); + e << boost::log::ipc::object_name_info(m_impl->name()); throw; } } @@ -722,7 +722,7 @@ BOOST_LOG_API void reliable_message_queue::reset_local() } catch (boost::exception& e) { - e << boost::log::resource_name_info(m_impl->name()); + e << boost::log::ipc::object_name_info(m_impl->name()); throw; } } @@ -742,7 +742,7 @@ BOOST_LOG_API reliable_message_queue::operation_result reliable_message_queue::s } catch (boost::exception& e) { - e << boost::log::resource_name_info(m_impl->name()); + e << boost::log::ipc::object_name_info(m_impl->name()); throw; } } @@ -756,7 +756,7 @@ BOOST_LOG_API bool reliable_message_queue::try_send(void const* message_data, ui } catch (boost::exception& e) { - e << boost::log::resource_name_info(m_impl->name()); + e << boost::log::ipc::object_name_info(m_impl->name()); throw; } } @@ -770,7 +770,7 @@ BOOST_LOG_API reliable_message_queue::operation_result reliable_message_queue::d } catch (boost::exception& e) { - e << boost::log::resource_name_info(m_impl->name()); + e << boost::log::ipc::object_name_info(m_impl->name()); throw; } } @@ -784,7 +784,7 @@ BOOST_LOG_API bool reliable_message_queue::do_try_receive(receive_handler handle } catch (boost::exception& e) { - e << boost::log::resource_name_info(m_impl->name()); + e << boost::log::ipc::object_name_info(m_impl->name()); throw; } } @@ -801,7 +801,7 @@ BOOST_LOG_API void reliable_message_queue::fixed_buffer_receive_handler(void* st p->size -= size; } -BOOST_LOG_API void reliable_message_queue::remove(const char*) +BOOST_LOG_API void reliable_message_queue::remove(object_name const&) { // System objects are reference counted on Windows, nothing to do here } diff --git a/src/windows/ipc_sync_wrappers.hpp b/src/windows/ipc_sync_wrappers.hpp index 537e763..1573704 100644 --- a/src/windows/ipc_sync_wrappers.hpp +++ b/src/windows/ipc_sync_wrappers.hpp @@ -41,6 +41,7 @@ #include #include #include +#include "windows/auto_handle.hpp" #include namespace boost { @@ -159,45 +160,6 @@ BOOST_FORCEINLINE bool bit_test_and_reset(boost::atomic< uint32_t >& x, uint32_t #endif -//! Converts UTF-8 to UTF-16 -std::wstring utf8_to_utf16(const char* str); - -//! A wrapper around a kernel object handle. Automatically closes the handle on destruction. -class auto_handle -{ -private: - boost::detail::winapi::HANDLE_ m_handle; - -public: - explicit auto_handle(boost::detail::winapi::HANDLE_ h = NULL) BOOST_NOEXCEPT : m_handle(h) - { - } - - ~auto_handle() BOOST_NOEXCEPT - { - if (m_handle) - BOOST_VERIFY(boost::detail::winapi::CloseHandle(m_handle) != 0); - } - - void init(boost::detail::winapi::HANDLE_ h) BOOST_NOEXCEPT - { - BOOST_ASSERT(m_handle == NULL); - m_handle = h; - } - - boost::detail::winapi::HANDLE_ get() const BOOST_NOEXCEPT { return m_handle; } - - void swap(auto_handle& that) BOOST_NOEXCEPT - { - boost::detail::winapi::HANDLE_ h = m_handle; - m_handle = that.m_handle; - that.m_handle = h; - } - - BOOST_DELETED_FUNCTION(auto_handle(auto_handle const&)) - BOOST_DELETED_FUNCTION(auto_handle& operator=(auto_handle const&)) -}; - //! Interprocess event object class interprocess_event { diff --git a/src/windows/object_name.cpp b/src/windows/object_name.cpp new file mode 100644 index 0000000..2664549 --- /dev/null +++ b/src/windows/object_name.cpp @@ -0,0 +1,200 @@ +/* + * Copyright Andrey Semashev 2016. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ +/*! + * \file windows/object_name.cpp + * \author Andrey Semashev + * \date 06.03.2016 + * + * \brief This header is the Boost.Log library implementation, see the library documentation + * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "windows/auto_handle.hpp" +#include + +namespace boost { + +BOOST_LOG_OPEN_NAMESPACE + +namespace ipc { + +BOOST_LOG_ANONYMOUS_NAMESPACE { + +#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_VISTA + +class auto_boundary_descriptor +{ +private: + HANDLE m_handle; + +public: + explicit auto_boundary_descriptor(HANDLE h = NULL) BOOST_NOEXCEPT : m_handle(h) + { + } + + ~auto_boundary_descriptor() BOOST_NOEXCEPT + { + if (m_handle) + DeleteBoundaryDescriptor(m_handle); + } + + void init(HANDLE h) BOOST_NOEXCEPT + { + BOOST_ASSERT(m_handle == NULL); + m_handle = h; + } + + HANDLE get() const BOOST_NOEXCEPT { return m_handle; } + HANDLE* get_ptr() const BOOST_NOEXCEPT { return &m_handle; } + + void swap(auto_boundary_descriptor& that) BOOST_NOEXCEPT + { + HANDLE h = m_handle; + m_handle = that.m_handle; + that.m_handle = h; + } + + BOOST_DELETED_FUNCTION(auto_boundary_descriptor(auto_boundary_descriptor const&)) + BOOST_DELETED_FUNCTION(auto_boundary_descriptor& operator=(auto_boundary_descriptor const&)) +}; + +//! Handle for the private namespace for \c user scope +static boost::atomic< HANDLE > g_user_private_namespace; + +//! Attempts to create or open the private namespace +bool init_user_namespace() +{ + HANDLE h = g_user_private_namespace.load(boost::memory_order_acquire); + if (BOOST_UNLIKELY(!h)) + { + // Obtain the current user SID + auto_handle h_process_token; + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, h_process_token.get_ptr())) + return false; + + TOKEN_USER token_user = {}; + DWORD token_user_size = 0; + if (!GetTokenInformation(h_process_token.get(), TokenUser, &token_user, sizeof(token_user), &token_user_size) || !token_user.User.Sid) + return false; + + // Create a boindary descriptor with the user's SID + auto_boundary_descriptor h_boundary(CreateBoundaryDescriptorW(L"User", 0)); + if (!h_boundary.get()) + return false; + + if (!AddSIDToBoundaryDescriptor(h_boundary.get_ptr(), token_user.User.Sid)) + return false; + + // Create or open a namespace for kernel objects + h = CreatePrivateNamespaceW(NULL, h_boundary.get(), L"User"); + if (!h) + h = OpenPrivateNamespace(h_boundary.get(), L"User"); + + if (h) + { + HANDLE expected = NULL; + if (!g_user_private_namespace.compare_exchange_strong(expected, h, boost::memory_order_acq_rel, boost::memory_order_acquire)) + { + ClosePrivateNamespace(h, 0); + h = expected; + } + } + } + + return !!h; +} + +#endif // BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_VISTA + +//! Returns a prefix string for a shared resource according to the scope +std::string get_scope_prefix(object_name::scope ns) +{ + std::string prefix; + switch (ns) + { + case object_name::process_group: + { + // For now consider all processes as members of the common process group. It may change if there is found + // a way to get a process group id (i.e. id of the closest parent process that was created with the CREATE_NEW_PROCESS_GROUP flag). + prefix = "Local\\boost.log.process_group"; + } + break; + + case object_name::session: + { + prefix = "Local\\boost.log.session"; + } + break; + + case object_name::user: + { +#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_VISTA + if (init_user_namespace()) + { + prefix = "User\\boost.log.user"; + } + else +#endif // BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_VISTA + { + wchar_t buf[UNLEN + 1u]; + ULONG len = sizeof(buf) / sizeof(*buf); + if (BOOST_UNLIKELY(!GetUserNameEx(NameSamCompatible, buf, &len))) + { + const boost::detail::winapi::DWORD_ err = boost::detail::winapi::GetLastError(); + BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to obtain the current user name", (err)); + } + + std::replace(buf, buf + len, L'\\', L'.'); + + prefix = "Local\\boost.log.user." + utf16_to_utf8(buf); + } + } + break; + + default: + prefix = "Global\\boost.log.global"; + break; + } + + prefix.push_back('.'); + + return boost::move(prefix); +} + +} // namespace + +//! Constructor from the object name +BOOST_LOG_API object_name::object_name(scope ns, const char* str) : + m_name(get_scope_prefix(ns) + str) +{ +} + +//! Constructor from the object name +BOOST_LOG_API object_name::object_name(scope ns, std::string const& str) : + m_name(get_scope_prefix(ns) + str) +{ +} + +} // namespace ipc + +BOOST_LOG_CLOSE_NAMESPACE // namespace log + +} // namespace boost + +#include diff --git a/src/windows/utf_code_conversion.hpp b/src/windows/utf_code_conversion.hpp index a7f4c10..7b00f13 100644 --- a/src/windows/utf_code_conversion.hpp +++ b/src/windows/utf_code_conversion.hpp @@ -28,6 +28,8 @@ namespace aux { //! Converts UTF-8 to UTF-16 std::wstring utf8_to_utf16(const char* str); +//! Converts UTF-16 to UTF-8 +std::string utf16_to_utf8(const wchar_t* str); } // namespace aux diff --git a/test/run/sink_text_ipc_mq_backend.cpp b/test/run/sink_text_ipc_mq_backend.cpp index f5ff459..e94463e 100644 --- a/test/run/sink_text_ipc_mq_backend.cpp +++ b/test/run/sink_text_ipc_mq_backend.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -25,7 +26,7 @@ #include "make_record.hpp" #include "char_definitions.hpp" -const char ipc_queue_name[] = "boost_log_test_text_ipc_mq_backend"; +const boost::log::ipc::object_name ipc_queue_name(boost::log::ipc::object_name::session, "boost_log_test_text_ipc_mq_backend"); const unsigned int capacity = 512; const unsigned int block_size = 1024; const char message[] = "Hello, world!"; diff --git a/test/run/util_ipc_object_name.cpp b/test/run/util_ipc_object_name.cpp new file mode 100644 index 0000000..32c9a16 --- /dev/null +++ b/test/run/util_ipc_object_name.cpp @@ -0,0 +1,160 @@ +/* + * Copyright Andrey Semashev 2016. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ +/*! + * \file util_ipc_object_name.cpp + * \author Andrey Semashev + * \date 07.03.2016 + * + * \brief The test verifies that \c ipc::object_name works. + */ + +#define BOOST_TEST_MODULE util_ipc_object_name + +#include +#include +#include +#include +#include +#include "char_definitions.hpp" + +const char test_object_name1[] = "boost_log_test_object_name1"; +const char test_object_name2[] = "boost_log_test_object_name2"; + +BOOST_AUTO_TEST_CASE(basic_functionality) +{ + // Default constructor. + { + boost::log::ipc::object_name name; + BOOST_CHECK(name.empty()); + BOOST_CHECK(equal_strings(name.c_str(), "")); + } + + // Initializing constructor + { + boost::log::ipc::object_name name(boost::log::ipc::object_name::global, test_object_name1); + BOOST_CHECK(!name.empty()); + } + + // Copy constructor + { + boost::log::ipc::object_name name1(boost::log::ipc::object_name::global, test_object_name1); + boost::log::ipc::object_name name2 = name1; + BOOST_CHECK_EQUAL(name1, name2); + } + + // Move constructor + { + boost::log::ipc::object_name name1(boost::log::ipc::object_name::global, test_object_name1); + std::string name_str = name1.c_str(); + boost::log::ipc::object_name name2 = boost::move(name1); + BOOST_CHECK(equal_strings(name2.c_str(), name_str.c_str())); + } + + // Copy assignment + { + boost::log::ipc::object_name name1(boost::log::ipc::object_name::global, test_object_name1); + boost::log::ipc::object_name name2; + name2 = name1; + BOOST_CHECK_EQUAL(name1, name2); + } + + // Move assignment + { + boost::log::ipc::object_name name1(boost::log::ipc::object_name::global, test_object_name1); + std::string name_str = name1.c_str(); + boost::log::ipc::object_name name2; + name2 = boost::move(name1); + BOOST_CHECK(equal_strings(name2.c_str(), name_str.c_str())); + } + + // Output + { + std::cout << boost::log::ipc::object_name(boost::log::ipc::object_name::global, test_object_name1) << std::endl; + std::cout << boost::log::ipc::object_name(boost::log::ipc::object_name::user, test_object_name1) << std::endl; + std::cout << boost::log::ipc::object_name(boost::log::ipc::object_name::session, test_object_name1) << std::endl; + std::cout << boost::log::ipc::object_name(boost::log::ipc::object_name::process_group, test_object_name1) << std::endl; + } +} + +BOOST_AUTO_TEST_CASE(name_equivalence) +{ + // Test that the same names are equal + { + boost::log::ipc::object_name name1(boost::log::ipc::object_name::global, test_object_name1); + boost::log::ipc::object_name name2(boost::log::ipc::object_name::global, test_object_name1); + BOOST_CHECK_EQUAL(name1, name2); + } + { + boost::log::ipc::object_name name1(boost::log::ipc::object_name::user, test_object_name1); + boost::log::ipc::object_name name2(boost::log::ipc::object_name::user, test_object_name1); + BOOST_CHECK_EQUAL(name1, name2); + } + { + boost::log::ipc::object_name name1(boost::log::ipc::object_name::session, test_object_name1); + boost::log::ipc::object_name name2(boost::log::ipc::object_name::session, test_object_name1); + BOOST_CHECK_EQUAL(name1, name2); + } + { + boost::log::ipc::object_name name1(boost::log::ipc::object_name::process_group, test_object_name1); + boost::log::ipc::object_name name2(boost::log::ipc::object_name::process_group, test_object_name1); + BOOST_CHECK_EQUAL(name1, name2); + } + + // Test that different names don't clash + { + boost::log::ipc::object_name name1(boost::log::ipc::object_name::global, test_object_name1); + boost::log::ipc::object_name name2(boost::log::ipc::object_name::global, test_object_name2); + BOOST_CHECK_NE(name1, name2); + } + { + boost::log::ipc::object_name name1(boost::log::ipc::object_name::user, test_object_name1); + boost::log::ipc::object_name name2(boost::log::ipc::object_name::user, test_object_name2); + BOOST_CHECK_NE(name1, name2); + } + { + boost::log::ipc::object_name name1(boost::log::ipc::object_name::session, test_object_name1); + boost::log::ipc::object_name name2(boost::log::ipc::object_name::session, test_object_name2); + BOOST_CHECK_NE(name1, name2); + } + { + boost::log::ipc::object_name name1(boost::log::ipc::object_name::process_group, test_object_name1); + boost::log::ipc::object_name name2(boost::log::ipc::object_name::process_group, test_object_name2); + BOOST_CHECK_NE(name1, name2); + } + + // Test that same named in different scopes don't clash + { + boost::log::ipc::object_name name1(boost::log::ipc::object_name::global, test_object_name1); + boost::log::ipc::object_name name2(boost::log::ipc::object_name::user, test_object_name1); + BOOST_CHECK_NE(name1, name2); + } + { + boost::log::ipc::object_name name1(boost::log::ipc::object_name::global, test_object_name1); + boost::log::ipc::object_name name2(boost::log::ipc::object_name::session, test_object_name1); + BOOST_CHECK_NE(name1, name2); + } + { + boost::log::ipc::object_name name1(boost::log::ipc::object_name::global, test_object_name1); + boost::log::ipc::object_name name2(boost::log::ipc::object_name::process_group, test_object_name1); + BOOST_CHECK_NE(name1, name2); + } + { + boost::log::ipc::object_name name1(boost::log::ipc::object_name::user, test_object_name1); + boost::log::ipc::object_name name2(boost::log::ipc::object_name::session, test_object_name1); + BOOST_CHECK_NE(name1, name2); + } + { + boost::log::ipc::object_name name1(boost::log::ipc::object_name::user, test_object_name1); + boost::log::ipc::object_name name2(boost::log::ipc::object_name::process_group, test_object_name1); + BOOST_CHECK_NE(name1, name2); + } + { + boost::log::ipc::object_name name1(boost::log::ipc::object_name::session, test_object_name1); + boost::log::ipc::object_name name2(boost::log::ipc::object_name::process_group, test_object_name1); + BOOST_CHECK_NE(name1, name2); + } +} diff --git a/test/run/util_ipc_reliable_mq.cpp b/test/run/util_ipc_reliable_mq.cpp index 0908588..dca517f 100644 --- a/test/run/util_ipc_reliable_mq.cpp +++ b/test/run/util_ipc_reliable_mq.cpp @@ -1,6 +1,6 @@ /* * Copyright Lingxi Li 2015. - * Copyright Andrey Semashev 2015. + * Copyright Andrey Semashev 2016. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) @@ -17,6 +17,7 @@ #define BOOST_TEST_MODULE util_ipc_reliable_mq #include +#include #include #include #include @@ -38,7 +39,7 @@ #endif #include "char_definitions.hpp" -const char ipc_queue_name[] = "boost_log_test_ipc_reliable_mq"; +const boost::log::ipc::object_name ipc_queue_name(boost::log::ipc::object_name::session, "boost_log_test_ipc_reliable_mq"); const unsigned int capacity = 512; const unsigned int block_size = 1024; const char message1[] = "Hello, world!"; @@ -71,7 +72,7 @@ BOOST_AUTO_TEST_CASE(basic_functionality) // Create constructor and destructor. { queue_t queue(boost::log::open_mode::create_only, ipc_queue_name, capacity, block_size); - BOOST_CHECK(equal_strings(queue.name(), ipc_queue_name)); + BOOST_CHECK(equal_strings(queue.name().c_str(), ipc_queue_name.c_str())); BOOST_CHECK(queue.is_open()); BOOST_CHECK_EQUAL(queue.capacity(), capacity); BOOST_CHECK_EQUAL(queue.block_size(), block_size); @@ -96,13 +97,13 @@ BOOST_AUTO_TEST_CASE(basic_functionality) queue_t queue_b(boost::log::open_mode::open_or_create, ipc_queue_name, capacity * 2u, block_size * 2u); // queue geometry differs from the existing queue BOOST_CHECK(queue_b.is_open()); - BOOST_CHECK(equal_strings(queue_b.name(), ipc_queue_name)); + BOOST_CHECK(equal_strings(queue_b.name().c_str(), ipc_queue_name.c_str())); BOOST_CHECK_EQUAL(queue_b.capacity(), capacity); BOOST_CHECK_EQUAL(queue_b.block_size(), block_size); queue_t queue_c(boost::log::open_mode::open_only, ipc_queue_name); BOOST_CHECK(queue_c.is_open()); - BOOST_CHECK(equal_strings(queue_c.name(), ipc_queue_name)); + BOOST_CHECK(equal_strings(queue_c.name().c_str(), ipc_queue_name.c_str())); BOOST_CHECK_EQUAL(queue_c.capacity(), capacity); BOOST_CHECK_EQUAL(queue_c.block_size(), block_size); } @@ -121,7 +122,7 @@ BOOST_AUTO_TEST_CASE(basic_functionality) queue_t queue_a(boost::log::open_mode::create_only, ipc_queue_name, capacity, block_size); queue_t queue_b(boost::move(queue_a)); BOOST_CHECK(!queue_a.is_open()); - BOOST_CHECK(equal_strings(queue_b.name(), ipc_queue_name)); + BOOST_CHECK(equal_strings(queue_b.name().c_str(), ipc_queue_name.c_str())); BOOST_CHECK(queue_b.is_open()); BOOST_CHECK_EQUAL(queue_b.capacity(), capacity); BOOST_CHECK_EQUAL(queue_b.block_size(), block_size); @@ -132,7 +133,7 @@ BOOST_AUTO_TEST_CASE(basic_functionality) queue_t queue_b; queue_b = boost::move(queue_a); BOOST_CHECK(!queue_a.is_open()); - BOOST_CHECK(equal_strings(queue_b.name(), ipc_queue_name)); + BOOST_CHECK(equal_strings(queue_b.name().c_str(), ipc_queue_name.c_str())); BOOST_CHECK(queue_b.is_open()); BOOST_CHECK_EQUAL(queue_b.capacity(), capacity); BOOST_CHECK_EQUAL(queue_b.block_size(), block_size); @@ -142,7 +143,7 @@ BOOST_AUTO_TEST_CASE(basic_functionality) queue_t queue_a(boost::log::open_mode::create_only, ipc_queue_name, capacity, block_size); queue_a.swap(queue_a); BOOST_CHECK(queue_a.is_open()); - BOOST_CHECK(equal_strings(queue_a.name(), ipc_queue_name)); + BOOST_CHECK(equal_strings(queue_a.name().c_str(), ipc_queue_name.c_str())); BOOST_CHECK_EQUAL(queue_a.capacity(), capacity); BOOST_CHECK_EQUAL(queue_a.block_size(), block_size); @@ -150,7 +151,7 @@ BOOST_AUTO_TEST_CASE(basic_functionality) swap(queue_a, queue_b); BOOST_CHECK(!queue_a.is_open()); BOOST_CHECK(queue_b.is_open()); - BOOST_CHECK(equal_strings(queue_b.name(), ipc_queue_name)); + BOOST_CHECK(equal_strings(queue_b.name().c_str(), ipc_queue_name.c_str())); BOOST_CHECK_EQUAL(queue_b.capacity(), capacity); BOOST_CHECK_EQUAL(queue_b.block_size(), block_size); }