diff options
Diffstat (limited to 'include')
28 files changed, 590 insertions, 214 deletions
diff --git a/include/CommonAPI/DBus/DBusAttribute.hpp b/include/CommonAPI/DBus/DBusAttribute.hpp index ba3ca77..2fd5bd3 100644 --- a/include/CommonAPI/DBus/DBusAttribute.hpp +++ b/include/CommonAPI/DBus/DBusAttribute.hpp @@ -10,7 +10,6 @@ #ifndef COMMONAPI_DBUS_DBUS_ATTRIBUTE_HPP_ #define COMMONAPI_DBUS_DBUS_ATTRIBUTE_HPP_ -#include <cassert> #include <cstdint> #include <tuple> @@ -35,7 +34,9 @@ public: getMethodName_(getMethodName), setMethodSignature_(setMethodSignature), depl_(_depl) { - assert(getMethodName); + if (NULL == getMethodName) { + COMMONAPI_ERROR(std::string(__FUNCTION__) + ": getMethodName is NULL"); + } } void getValue(CommonAPI::CallStatus &_status, ValueType &_value, const CommonAPI::CallInfo *_info) const { @@ -84,8 +85,12 @@ public: : DBusReadonlyAttribute<AttributeType_, AttributeDepl_>(_proxy, _setMethodSignature, _getMethodName, _depl), setMethodName_(_setMethodName), setMethodSignature_(_setMethodSignature) { - assert(_setMethodName); - assert(_setMethodSignature); + if (NULL == _setMethodName) { + COMMONAPI_ERROR(std::string(__FUNCTION__) + ": _setMethodName is NULL"); + } + if (NULL == _setMethodSignature) { + COMMONAPI_ERROR(std::string(__FUNCTION__) + ": _setMethodSignature is NULL"); + } } void setValue(const ValueType &_request, CommonAPI::CallStatus &_status, ValueType &_response, const CommonAPI::CallInfo *_info) { diff --git a/include/CommonAPI/DBus/DBusClientId.hpp b/include/CommonAPI/DBus/DBusClientId.hpp index 02e369f..982b4dd 100644 --- a/include/CommonAPI/DBus/DBusClientId.hpp +++ b/include/CommonAPI/DBus/DBusClientId.hpp @@ -24,7 +24,7 @@ class DBusMessage; * This class represents the DBus specific implementation of CommonAPI::ClientId. * It internally uses a string to identify clients. This string is the unique sender id used by dbus. */ -class DBusClientId +class COMMONAPI_EXPORT_CLASS_EXPLICIT DBusClientId : public CommonAPI::ClientId { friend struct std::hash<DBusClientId>; diff --git a/include/CommonAPI/DBus/DBusConfig.hpp b/include/CommonAPI/DBus/DBusConfig.hpp index dae6b7a..cb07461 100644 --- a/include/CommonAPI/DBus/DBusConfig.hpp +++ b/include/CommonAPI/DBus/DBusConfig.hpp @@ -15,8 +15,7 @@ namespace CommonAPI { namespace DBus { -static const Timeout_t DEFAULT_SEND_TIMEOUT_MS = 5000; -static CommonAPI::CallInfo defaultCallInfo(DEFAULT_SEND_TIMEOUT_MS); +static CommonAPI::CallInfo defaultCallInfo(CommonAPI::DEFAULT_SEND_TIMEOUT_MS); } // namespace DBus } // namespace CommonAPI diff --git a/include/CommonAPI/DBus/DBusConnection.hpp b/include/CommonAPI/DBus/DBusConnection.hpp index f2fd516..f79dc27 100644 --- a/include/CommonAPI/DBus/DBusConnection.hpp +++ b/include/CommonAPI/DBus/DBusConnection.hpp @@ -45,12 +45,14 @@ friend class DBusConnection; }; struct WatchContext { - WatchContext(std::weak_ptr<MainLoopContext> mainLoopContext, DispatchSource* dispatchSource) : - mainLoopContext_(mainLoopContext), dispatchSource_(dispatchSource) { + WatchContext(std::weak_ptr<MainLoopContext> mainLoopContext, DispatchSource* dispatchSource, + std::weak_ptr<DBusConnection> dbusConnection) : + mainLoopContext_(mainLoopContext), dispatchSource_(dispatchSource), dbusConnection_(dbusConnection) { } std::weak_ptr<MainLoopContext> mainLoopContext_; DispatchSource* dispatchSource_; + std::weak_ptr<DBusConnection> dbusConnection_; }; class DBusConnection @@ -107,13 +109,13 @@ public: DBusSignalHandler* dbusSignalHandler, const bool justAddFilter = false); - COMMONAPI_EXPORT DBusProxyConnection::DBusSignalHandlerToken subscribeForSelectiveBroadcast(bool& subscriptionAccepted, - const std::string& objectPath, - const std::string& interfaceName, - const std::string& interfaceMemberName, - const std::string& interfaceMemberSignature, - DBusSignalHandler* dbusSignalHandler, - DBusProxy* callingProxy); + COMMONAPI_EXPORT void subscribeForSelectiveBroadcast(const std::string& objectPath, + const std::string& interfaceName, + const std::string& interfaceMemberName, + const std::string& interfaceMemberSignature, + DBusSignalHandler* dbusSignalHandler, + DBusProxy* callingProxy, + uint32_t tag); COMMONAPI_EXPORT void unsubscribeFromSelectiveBroadcast(const std::string& eventName, DBusProxyConnection::DBusSignalHandlerToken subscription, @@ -136,11 +138,21 @@ public: COMMONAPI_EXPORT bool isDispatchReady(); COMMONAPI_EXPORT bool singleDispatch(); + COMMONAPI_EXPORT void dispatchDBusMessageReply(const DBusMessage& _reply, + DBusMessageReplyAsyncHandler* _dbusMessageReplyAsyncHandler); COMMONAPI_EXPORT virtual bool hasDispatchThread(); COMMONAPI_EXPORT virtual const ConnectionId_t& getConnectionId() const; + COMMONAPI_EXPORT void incrementConnection(); + COMMONAPI_EXPORT void decrementConnection(); + + COMMONAPI_EXPORT bool setDispatching(bool isDispatching); + + COMMONAPI_EXPORT void pushDBusMessageReply(const DBusMessage& _reply, + std::unique_ptr<DBusMessageReplyAsyncHandler> _dbusMessageReplyAsyncHandler); + #ifdef COMMONAPI_DBUS_TEST inline std::weak_ptr<DBusMainloop> getLoop() { return loop_; } #endif @@ -149,21 +161,29 @@ public: typedef std::pair<uint32_t, std::string> DBusSignalMatchRuleMapping; typedef std::unordered_map<DBusSignalMatchRuleTuple, DBusSignalMatchRuleMapping> DBusSignalMatchRulesMap; private: + + struct PendingCallNotificationData { + PendingCallNotificationData(const DBusConnection* _dbusConnection, + DBusMessageReplyAsyncHandler* _replyAsyncHandler) : + dbusConnection_(_dbusConnection), + replyAsyncHandler_(_replyAsyncHandler) { } + + const DBusConnection* dbusConnection_; + DBusMessageReplyAsyncHandler* replyAsyncHandler_; + }; + COMMONAPI_EXPORT void dispatch(); COMMONAPI_EXPORT void suspendDispatching() const; COMMONAPI_EXPORT void resumeDispatching() const; std::thread* dispatchThread_; - bool stopDispatching_; std::weak_ptr<MainLoopContext> mainLoopContext_; + DBusMessageWatch* msgWatch_; + DBusMessageDispatchSource* msgDispatchSource_; DispatchSource* dispatchSource_; WatchContext* watchContext_; - mutable std::recursive_mutex sendLock_; - mutable bool pauseDispatching_; - mutable std::mutex dispatchSuspendLock_; - COMMONAPI_EXPORT void addLibdbusSignalMatchRule(const std::string& objectPath, const std::string& interfaceName, const std::string& interfaceMemberName, @@ -179,9 +199,11 @@ public: COMMONAPI_EXPORT void initLibdbusObjectPathHandlerAfterConnect(); ::DBusHandlerResult onLibdbusObjectPathMessage(::DBusMessage* libdbusMessage); - COMMONAPI_EXPORT static DBusMessage convertToDBusMessage(::DBusPendingCall* _libdbusPendingCall, - CallStatus& _callStatus); + COMMONAPI_EXPORT static DBusMessage convertToDBusMessage(::DBusPendingCall* _libdbusPendingCall); COMMONAPI_EXPORT static void onLibdbusPendingCallNotifyThunk(::DBusPendingCall* libdbusPendingCall, void* userData); + void onLibdbusPendingCall(::DBusPendingCall* _libdbusPendingCall, + const DBusMessage& _reply, + DBusMessageReplyAsyncHandler* _dbusMessageReplyAsyncHandler) const; COMMONAPI_EXPORT static void onLibdbusDataCleanup(void* userData); COMMONAPI_EXPORT static ::DBusHandlerResult onLibdbusObjectPathMessageThunk(::DBusConnection* libdbusConnection, @@ -205,7 +227,8 @@ public: COMMONAPI_EXPORT void enforceAsynchronousTimeouts() const; COMMONAPI_EXPORT static const DBusObjectPathVTable* getDBusObjectPathVTable(); - COMMONAPI_EXPORT bool sendPendingSelectiveSubscription(DBusProxy* proxy, std::string methodName); + COMMONAPI_EXPORT void sendPendingSelectiveSubscription(DBusProxy* proxy, std::string methodName, + DBusSignalHandler* dbusSignalHandler, uint32_t tag); ::DBusConnection* connection_; mutable std::mutex connectionGuard_; @@ -284,6 +307,16 @@ public: mutable std::set<DBusMessageReplyAsyncHandler*> timeoutInfiniteAsyncHandlers_; mutable std::mutex timeoutInfiniteAsyncHandlersMutex_; + uint32_t activeConnections_; + mutable std::mutex activeConnectionsMutex_; + + bool isDisconnecting_; + bool isDispatching_; + bool isWaitingOnFinishedDispatching_; + + std::set<std::thread::id> dispatchThreads_; + std::mutex dispatchMutex_; + std::condition_variable dispatchCondition_; }; diff --git a/include/CommonAPI/DBus/DBusDaemonProxy.hpp b/include/CommonAPI/DBus/DBusDaemonProxy.hpp index 69541b6..0652654 100644 --- a/include/CommonAPI/DBus/DBusDaemonProxy.hpp +++ b/include/CommonAPI/DBus/DBusDaemonProxy.hpp @@ -34,8 +34,14 @@ class StaticInterfaceVersionAttribute: public InterfaceVersionAttribute { Version version_; }; +#ifndef DBUS_DAEMON_PROXY_DEFAULT_SEND_TIMEOUT +#define DBUS_DAEMON_PROXY_DEFAULT_SEND_TIMEOUT 10000 +#endif + +static const CommonAPI::CallInfo daemonProxyInfo(DBUS_DAEMON_PROXY_DEFAULT_SEND_TIMEOUT); -class DBusDaemonProxy : public DBusProxyBase { +class DBusDaemonProxy : public DBusProxyBase, + public std::enable_shared_from_this<DBusDaemonProxy> { public: typedef Event<std::string, std::string, std::string> NameOwnerChangedEvent; @@ -53,6 +59,10 @@ class DBusDaemonProxy : public DBusProxyBase { COMMONAPI_EXPORT virtual bool isAvailable() const; COMMONAPI_EXPORT virtual bool isAvailableBlocking() const; + COMMONAPI_EXPORT virtual std::future<AvailabilityStatus> isAvailableAsync( + isAvailableAsyncCallback _callback, + const CallInfo *_info) const; + COMMONAPI_EXPORT virtual ProxyStatusEvent& getProxyStatusEvent(); COMMONAPI_EXPORT virtual InterfaceVersionAttribute& getInterfaceVersionAttribute(); @@ -64,14 +74,54 @@ class DBusDaemonProxy : public DBusProxyBase { COMMONAPI_EXPORT NameOwnerChangedEvent& getNameOwnerChangedEvent(); COMMONAPI_EXPORT void listNames(CommonAPI::CallStatus& callStatus, std::vector<std::string>& busNames) const; - COMMONAPI_EXPORT std::future<CallStatus> listNamesAsync(ListNamesAsyncCallback listNamesAsyncCallback) const; + + template <typename DelegateObjectType> + COMMONAPI_EXPORT std::future<CallStatus> listNamesAsync(typename DBusProxyAsyncCallbackHandler<DelegateObjectType, + std::vector<std::string>>::Delegate& delegate) const { + DBusMessage dbusMessage = createMethodCall("ListNames", ""); + return getDBusConnection()->sendDBusMessageWithReplyAsync( + dbusMessage, + DBusProxyAsyncCallbackHandler<DelegateObjectType, std::vector<std::string>>::create(delegate, std::tuple<std::vector<std::string>>()), + &daemonProxyInfo); + } COMMONAPI_EXPORT void nameHasOwner(const std::string& busName, CommonAPI::CallStatus& callStatus, bool& hasOwner) const; - COMMONAPI_EXPORT std::future<CallStatus> nameHasOwnerAsync(const std::string& busName, - NameHasOwnerAsyncCallback nameHasOwnerAsyncCallback) const; + template <typename DelegateObjectType> + COMMONAPI_EXPORT std::future<CallStatus> nameHasOwnerAsync(const std::string& busName, + typename DBusProxyAsyncCallbackHandler<DelegateObjectType, + bool>::Delegate& delegate) const { + DBusMessage dbusMessage = createMethodCall("NameHasOwner", "s"); + + DBusOutputStream outputStream(dbusMessage); + const bool success = DBusSerializableArguments<std::string>::serialize(outputStream, busName); + if (!success) { + std::promise<CallStatus> promise; + promise.set_value(CallStatus::OUT_OF_MEMORY); + return promise.get_future(); + } + outputStream.flush(); + + return getDBusConnection()->sendDBusMessageWithReplyAsync( + dbusMessage, + DBusProxyAsyncCallbackHandler<DelegateObjectType, bool>::create(delegate, std::tuple<bool>()), + &daemonProxyInfo); + } + + template <typename DelegateObjectType> COMMONAPI_EXPORT std::future<CallStatus> getManagedObjectsAsync(const std::string& forDBusServiceName, - GetManagedObjectsAsyncCallback) const; + typename DBusProxyAsyncCallbackHandler<DelegateObjectType, + DBusObjectToInterfaceDict>::Delegate& delegate) const { + static DBusAddress address(forDBusServiceName, "/", "org.freedesktop.DBus.ObjectManager"); + auto dbusMethodCallMessage = DBusMessage::createMethodCall(address, "GetManagedObjects", ""); + + return getDBusConnection()->sendDBusMessageWithReplyAsync( + dbusMethodCallMessage, + DBusProxyAsyncCallbackHandler<DelegateObjectType, DBusObjectToInterfaceDict>::create( + delegate, std::tuple<DBusObjectToInterfaceDict>() + ), + &daemonProxyInfo); + } /** * Get the unique connection/bus name of the primary owner of the name given @@ -81,7 +131,26 @@ class DBusDaemonProxy : public DBusProxyBase { * * @return CallStatus::REMOTE_ERROR if the name is unknown, otherwise CallStatus::SUCCESS and the uniq name of the owner */ - std::future<CallStatus> getNameOwnerAsync(const std::string& busName, GetNameOwnerAsyncCallback getNameOwnerAsyncCallback) const; + template <typename DelegateObjectType> + std::future<CallStatus> getNameOwnerAsync(const std::string& busName, + typename DBusProxyAsyncCallbackHandler<DelegateObjectType, + std::string>::Delegate& delegate) const { + DBusMessage dbusMessage = createMethodCall("GetNameOwner", "s"); + + DBusOutputStream outputStream(dbusMessage); + const bool success = DBusSerializableArguments<std::string>::serialize(outputStream, busName); + if (!success) { + std::promise<CallStatus> promise; + promise.set_value(CallStatus::OUT_OF_MEMORY); + return promise.get_future(); + } + outputStream.flush(); + + return getDBusConnection()->sendDBusMessageWithReplyAsync( + dbusMessage, + DBusProxyAsyncCallbackHandler<DelegateObjectType, std::string>::create(delegate, std::tuple<std::string>()), + &daemonProxyInfo); + } private: DBusEvent<NameOwnerChangedEvent, std::string, std::string, std::string> nameOwnerChangedEvent_; diff --git a/include/CommonAPI/DBus/DBusFactory.hpp b/include/CommonAPI/DBus/DBusFactory.hpp index fda0129..6ce0c7e 100644 --- a/include/CommonAPI/DBus/DBusFactory.hpp +++ b/include/CommonAPI/DBus/DBusFactory.hpp @@ -10,6 +10,7 @@ #ifndef COMMONAPI_DBUS_FACTORY_HPP_ #define COMMONAPI_DBUS_FACTORY_HPP_ +#include <list> #include <map> #include <CommonAPI/Export.hpp> @@ -24,6 +25,8 @@ class DBusProxy; class DBusProxyConnection; class DBusStubAdapter; +typedef void (*InterfaceInitFunction)(void); + typedef std::shared_ptr<DBusProxy> (*ProxyCreateFunction)(const DBusAddress &_address, const std::shared_ptr<DBusProxyConnection> &_connection); @@ -40,6 +43,8 @@ public: COMMONAPI_EXPORT Factory(); COMMONAPI_EXPORT virtual ~Factory(); + COMMONAPI_EXPORT void init(); + COMMONAPI_EXPORT void registerProxyCreateMethod(const std::string &_address, ProxyCreateFunction _function); @@ -84,6 +89,13 @@ public: COMMONAPI_EXPORT bool registerManagedService(const std::shared_ptr<DBusStubAdapter> &_adapter); COMMONAPI_EXPORT bool unregisterManagedService(const std::string &_address); + COMMONAPI_EXPORT void incrementConnection(std::shared_ptr<DBusProxyConnection>); + COMMONAPI_EXPORT void decrementConnection(std::shared_ptr<DBusProxyConnection>); + COMMONAPI_EXPORT void releaseConnection(const ConnectionId_t&, MainLoopContext*); + + // Initialization + COMMONAPI_EXPORT void registerInterface(InterfaceInitFunction _function); + private: COMMONAPI_EXPORT std::shared_ptr<DBusConnection> getConnection(const ConnectionId_t &); COMMONAPI_EXPORT std::shared_ptr<DBusConnection> getConnection(std::shared_ptr<MainLoopContext>); @@ -97,7 +109,10 @@ private: private: static std::shared_ptr<Factory> theFactory; + std::mutex connectionsMutex_; std::map<ConnectionId_t, std::shared_ptr<DBusConnection>> connections_; + + std::mutex contextConnectionsMutex_; std::map<MainLoopContext *, std::shared_ptr<DBusConnection>> contextConnections_; std::map<std::string, ProxyCreateFunction> proxyCreateFunctions_; @@ -105,7 +120,9 @@ private: ServicesMap services_; - DBusType_t dBusBusType_; + std::list<InterfaceInitFunction> initializers_; + std::mutex initializerMutex_; + bool isInitialized_; }; } // namespace DBus diff --git a/include/CommonAPI/DBus/DBusFreedesktopPropertiesStub.hpp b/include/CommonAPI/DBus/DBusFreedesktopPropertiesStub.hpp index 1c01da9..bc31a89 100644 --- a/include/CommonAPI/DBus/DBusFreedesktopPropertiesStub.hpp +++ b/include/CommonAPI/DBus/DBusFreedesktopPropertiesStub.hpp @@ -47,7 +47,7 @@ private: std::weak_ptr<DBusProxyConnection> connection_; std::shared_ptr<DBusStubAdapter> adapter_; - typedef std::unordered_map<std::string, std::shared_ptr<DBusStubAdapter>> DBusInterfacesMap; + typedef std::unordered_map<std::string, std::vector<std::shared_ptr<DBusStubAdapter>>> DBusInterfacesMap; DBusInterfacesMap managedInterfaces_; std::mutex dbusInterfacesLock_; diff --git a/include/CommonAPI/DBus/DBusFreedesktopStubAdapterHelper.hpp b/include/CommonAPI/DBus/DBusFreedesktopStubAdapterHelper.hpp index 4593400..ec55f4e 100644 --- a/include/CommonAPI/DBus/DBusFreedesktopStubAdapterHelper.hpp +++ b/include/CommonAPI/DBus/DBusFreedesktopStubAdapterHelper.hpp @@ -13,6 +13,16 @@ #include <CommonAPI/Struct.hpp> #include <CommonAPI/DBus/DBusStubAdapterHelper.hpp> +# if _MSC_VER >= 1300 +/* +* Diamond inheritance is used for the DBusSetAttributeStubDispatcher base class. +* The Microsoft compiler put warning (C4250) using a desired c++ feature: "Delegating to a sister class" +* A powerful technique that arises from using virtual inheritance is to delegate a method from a class in another class +* by using a common abstract base class. This is also called cross delegation. +*/ +# pragma warning( disable : 4250 ) +# endif + namespace CommonAPI { namespace DBus { @@ -139,46 +149,26 @@ struct DBusStubFreedesktopPropertiesSignalHelper; template<typename DataType_, typename DeplType_> struct DBusStubFreedesktopPropertiesSignalHelper { - template <typename ValueType_> - struct DBusPropertiesEntry - : public CommonAPI::Struct<std::string, CommonAPI::Variant<ValueType_>> { - - DBusPropertiesEntry() = default; - DBusPropertiesEntry(const std::string &_propertyName, - const ValueType_ &_propertyValue) { - std::get<0>(this->values_) = _propertyName; - std::get<1>(this->values_) = _propertyValue; - }; - - const std::string &getPropertyName() const { return std::get<0>(this->values_); } - void setPropertyName(const std::string &_value) { std::get<0>(this->values_) = _value; } - - const ValueType_ getPropertyValue() const { return std::get<1>(this->values_); } - void setPropertyValue(const ValueType_ &_value) { std::get<1>(this->values_) = _value; } - }; - - typedef std::vector<DBusPropertiesEntry<DataType_>> PropertiesArray; - typedef CommonAPI::Deployment<CommonAPI::EmptyDeployment, VariantDeployment<DeplType_>> PropertyDeployment; - typedef CommonAPI::ArrayDeployment<PropertyDeployment> PropertiesDeployment; - typedef CommonAPI::Deployable<PropertiesArray, PropertiesDeployment> DeployedPropertiesArray; + typedef std::unordered_map<std::string, Variant<DataType_>> PropertyMap; + typedef MapDeployment<EmptyDeployment, VariantDeployment<DeplType_>> PropertyMapDeployment; + typedef Deployable<PropertyMap, PropertyMapDeployment> DeployedPropertyMap; template <typename StubClass_> static bool sendPropertiesChangedSignal(const StubClass_ &_stub, const std::string &_propertyName, const DataType_ &_inArg, DeplType_ *_depl) { const std::vector<std::string> invalidatedProperties; - PropertiesArray changedProperties; - DBusPropertiesEntry<DataType_> entry(_propertyName, _inArg); - changedProperties.push_back(entry); - VariantDeployment<DeplType_> actualDepl(true, _depl); - PropertyDeployment propertyDeployment(nullptr, &actualDepl); - PropertiesDeployment changedPropertiesDeployment(&propertyDeployment); + // fill out property map + PropertyMap changedProperties; + changedProperties[_propertyName] = _inArg; - DeployedPropertiesArray deployedChangedProperties(changedProperties, &changedPropertiesDeployment); + VariantDeployment<DeplType_> actualDepl(true, _depl); + PropertyMapDeployment changedPropertiesDeployment(nullptr, &actualDepl); + DeployedPropertyMap deployedChangedProperties(changedProperties, &changedPropertiesDeployment); return DBusStubSignalHelper< DBusSerializableArguments< const std::string, - DeployedPropertiesArray, + DeployedPropertyMap, std::vector<std::string> > >::sendSignal( diff --git a/include/CommonAPI/DBus/DBusInputStream.hpp b/include/CommonAPI/DBus/DBusInputStream.hpp index 9a3f74d..ec6c7d0 100644 --- a/include/CommonAPI/DBus/DBusInputStream.hpp +++ b/include/CommonAPI/DBus/DBusInputStream.hpp @@ -14,11 +14,11 @@ #include <iomanip> #include <sstream> -#include <cassert> #include <cstdint> #include <stack> #include <string> #include <vector> +#include <cstring> #include <CommonAPI/Export.hpp> #include <CommonAPI/InputStream.hpp> @@ -73,7 +73,7 @@ public: COMMONAPI_EXPORT InputStream &readValue(Version &_value, const EmptyDeployment *_depl); COMMONAPI_EXPORT void beginReadMapOfSerializableStructs() { - uint32_t itsSize; + uint32_t itsSize(0); _readValue(itsSize); pushSize(itsSize); align(8); /* correct alignment for first DICT_ENTRY */ @@ -90,10 +90,12 @@ public: } COMMONAPI_EXPORT InputStream &skipMap() { - uint32_t itsSize; + uint32_t itsSize(0); _readValue(itsSize); align(8); /* skip padding (if any) */ - assert(itsSize <= (sizes_.top() + positions_.top() - current_)); + if (itsSize > (sizes_.top() + positions_.top() - current_)) { + COMMONAPI_ERROR(std::string(__FUNCTION__) + ": size ", itsSize, " exceeds remaining ", (sizes_.top() + positions_.top() - current_)); + } _readRaw(itsSize); return (*this); } @@ -103,6 +105,10 @@ public: Base_ tmpValue; readValue(tmpValue, _depl); _value = tmpValue; + + if(!_value.validate()) { + setError(); + } return (*this); } @@ -118,7 +124,7 @@ public: template<class Deployment_, class PolymorphicStruct_> COMMONAPI_EXPORT InputStream &readValue(std::shared_ptr<PolymorphicStruct_> &_value, const Deployment_ *_depl) { - uint32_t serial; + uint32_t serial(0); align(8); _readValue(serial); skipSignature(); @@ -135,8 +141,13 @@ public: COMMONAPI_EXPORT InputStream &readValue(Variant<Types_...> &_value, const CommonAPI::EmptyDeployment *_depl = nullptr) { (void)_depl; if(_value.hasValue()) { - DeleteVisitor<_value.maxSize> visitor(_value.valueStorage_); - ApplyVoidVisitor<DeleteVisitor<_value.maxSize>, +#if _MSC_VER < 1900 + const auto maxSize = Variant<Types_...>::maxSize; +#else + constexpr auto maxSize = Variant<Types_...>::maxSize; +#endif + DeleteVisitor<maxSize> visitor(_value.valueStorage_); + ApplyVoidVisitor<DeleteVisitor<maxSize>, Variant<Types_...>, Types_... >::visit(visitor, _value); } @@ -154,8 +165,13 @@ public: template<typename Deployment_, typename... Types_> COMMONAPI_EXPORT InputStream &readValue(Variant<Types_...> &_value, const Deployment_ *_depl) { if(_value.hasValue()) { - DeleteVisitor<_value.maxSize> visitor(_value.valueStorage_); - ApplyVoidVisitor<DeleteVisitor<_value.maxSize>, +#if _MSC_VER < 1900 + const auto maxSize = Variant<Types_...>::maxSize; +#else + constexpr auto maxSize = Variant<Types_...>::maxSize; +#endif + DeleteVisitor<maxSize> visitor(_value.valueStorage_); + ApplyVoidVisitor<DeleteVisitor<maxSize>, Variant<Types_...>, Types_... >::visit(visitor, _value); } @@ -163,20 +179,32 @@ public: // Read signature uint8_t signatureLength; readValue(signatureLength, static_cast<EmptyDeployment *>(nullptr)); - std::string signature(_readRaw(signatureLength+1), signatureLength); - - // Determine index (value type) from signature - TypeCompareVisitor<Types_...> visitor(signature); - bool success = ApplyTypeCompareVisitor< - TypeCompareVisitor<Types_...>, - Variant<Types_...>, - Deployment_, - Types_... - >::visit(visitor, _value, _depl, _value.valueType_); - if (!success) { - _value.valueType_ = 0; // Invalid index - setError(); + char * raw = _readRaw(signatureLength+1); + if (hasError()) { return (*this); + } else { + std::string signature(raw, signatureLength); + + // Determine index (value type) from signature + TypeCompareVisitor<Types_...> visitor(signature); + bool success = ApplyTypeCompareVisitor< + TypeCompareVisitor<Types_...>, + Variant<Types_...>, + Deployment_, + Types_... + >::visit(visitor, _value, _depl, _value.valueType_); + /* + * It is possible that this ApplyTypeCompareVisitor fails on purpose, + * if the data type of the variant does not match the data type in the stream. + * This can happen for instance with the Freedesktop messages that return + * data in variants, but we don't have any idea _which variant_ until we've + * tried to stream the value in the ApplyTypeComputerVisitor. + */ + if (!success) { + _value.valueType_ = 0; // Invalid index signifying 'no value' + setError(); + return (*this); + } } } else { align(8); @@ -196,7 +224,7 @@ public: COMMONAPI_EXPORT InputStream &readValue(std::vector<ElementType_> &_value, const EmptyDeployment *_depl) { (void)_depl; - uint32_t itsSize; + uint32_t itsSize(0); _readValue(itsSize); pushSize(itsSize); @@ -222,9 +250,27 @@ public: return (*this); } + COMMONAPI_EXPORT InputStream &readValue(std::vector<uint8_t> &_value, const EmptyDeployment *_depl) { + (void)_depl; + + uint32_t itsSize(0); + _readValue(itsSize); + + alignVector<uint8_t>(); + + uint8_t *data = reinterpret_cast<uint8_t *>(_readRaw(itsSize)); + if (!hasError()) { + _value.resize(itsSize); + std::memcpy(_value.data(), data, itsSize); + } + + return (*this); + } + + template<class Deployment_, typename ElementType_> COMMONAPI_EXPORT InputStream &readValue(std::vector<ElementType_> &_value, const Deployment_ *_depl) { - uint32_t itsSize; + uint32_t itsSize(0); _readValue(itsSize); pushSize(itsSize); @@ -256,7 +302,7 @@ public: typedef typename std::unordered_map<KeyType_, ValueType_, HasherType_>::value_type MapElement; - uint32_t itsSize; + uint32_t itsSize(0); _readValue(itsSize); pushSize(itsSize); @@ -291,7 +337,7 @@ public: typedef typename std::unordered_map<KeyType_, ValueType_, HasherType_>::value_type MapElement; - uint32_t itsSize; + uint32_t itsSize(0); _readValue(itsSize); pushSize(itsSize); @@ -395,7 +441,10 @@ public: if (sizeof(_value) > 1) align(sizeof(Type_)); - _value = *(reinterpret_cast<Type_ *>(_readRaw(sizeof(Type_)))); + char * raw = _readRaw(sizeof(Type_)); + if (!hasError()) { + _value = *(reinterpret_cast<Type_ *>(raw)); + } return (*this); } @@ -403,7 +452,10 @@ public: COMMONAPI_EXPORT DBusInputStream &_readValue(float &_value) { align(sizeof(double)); - _value = (float) (*(reinterpret_cast<double*>(_readRaw(sizeof(double))))); + char * raw = _readRaw(sizeof(double)); + if (!hasError()) { + _value = (float) (*(reinterpret_cast<double*>(raw))); + } return (*this); } @@ -415,7 +467,7 @@ private: COMMONAPI_EXPORT size_t popSize(); inline void skipSignature() { - uint8_t length; + uint8_t length(0); _readValue(length); _readRaw(length + 1); } diff --git a/include/CommonAPI/DBus/DBusInstanceAvailabilityStatusChangedEvent.hpp b/include/CommonAPI/DBus/DBusInstanceAvailabilityStatusChangedEvent.hpp index 6c6c9e1..ec2d70f 100644 --- a/include/CommonAPI/DBus/DBusInstanceAvailabilityStatusChangedEvent.hpp +++ b/include/CommonAPI/DBus/DBusInstanceAvailabilityStatusChangedEvent.hpp @@ -80,14 +80,18 @@ class DBusInstanceAvailabilityStatusChangedEvent: DBusInterfacesAndPropertiesDict dbusInterfacesAndPropertiesDict; dbusInputStream >> dbusObjectPath; - assert(!dbusInputStream.hasError()); + if (dbusInputStream.hasError()) { + COMMONAPI_ERROR(std::string(__FUNCTION__) + " failed to read object path"); + } dbusInputStream.beginReadMapOfSerializableStructs(); while (!dbusInputStream.readMapCompleted()) { dbusInputStream.align(8); dbusInputStream >> dbusInterfaceName; dbusInputStream.skipMap(); - assert(!dbusInputStream.hasError()); + if (dbusInputStream.hasError()) { + COMMONAPI_ERROR(std::string(__FUNCTION__) + " failed to read interface name"); + } if(dbusInterfaceName == observedInterfaceName_) { notifyInterfaceStatusChanged(dbusObjectPath, dbusInterfaceName, AvailabilityStatus::AVAILABLE); } @@ -101,10 +105,14 @@ class DBusInstanceAvailabilityStatusChangedEvent: std::vector<std::string> dbusInterfaceNames; dbusInputStream >> dbusObjectPath; - assert(!dbusInputStream.hasError()); + if (dbusInputStream.hasError()) { + COMMONAPI_ERROR(std::string(__FUNCTION__) + " failed to read object path"); + } dbusInputStream >> dbusInterfaceNames; - assert(!dbusInputStream.hasError()); + if (dbusInputStream.hasError()) { + COMMONAPI_ERROR(std::string(__FUNCTION__) + " failed to read interface names"); + } for (const auto& dbusInterfaceName : dbusInterfaceNames) { if(dbusInterfaceName == observedInterfaceName_) { diff --git a/include/CommonAPI/DBus/DBusMainLoop.hpp b/include/CommonAPI/DBus/DBusMainLoop.hpp index 2fff847..b09a8f1 100755 --- a/include/CommonAPI/DBus/DBusMainLoop.hpp +++ b/include/CommonAPI/DBus/DBusMainLoop.hpp @@ -75,6 +75,8 @@ class DBusMainLoop { COMMONAPI_EXPORT void wakeup(); COMMONAPI_EXPORT void wakeupAck(); + COMMONAPI_EXPORT void cleanup(); + COMMONAPI_EXPORT void registerFileDescriptor(const DBusMainLoopPollFd& fileDescriptor); COMMONAPI_EXPORT void unregisterFileDescriptor(const DBusMainLoopPollFd& fileDescriptor); @@ -158,9 +160,9 @@ class DBusMainLoop { std::mutex watchesMutex_; std::mutex timeoutsMutex_; - std::set<DispatchSourceToDispatchStruct*> sourcesToDispatch_; - std::set<WatchToDispatchStruct*> watchesToDispatch_; - std::set<TimeoutToDispatchStruct*> timeoutsToDispatch_; + std::set<std::pair<DispatchPriority, DispatchSourceToDispatchStruct*>> sourcesToDispatch_; + std::set<std::pair<DispatchPriority, WatchToDispatchStruct*>> watchesToDispatch_; + std::set<std::pair<DispatchPriority, TimeoutToDispatchStruct*>> timeoutsToDispatch_; DispatchSourceListenerSubscription dispatchSourceListenerSubscription_; WatchListenerSubscription watchListenerSubscription_; diff --git a/include/CommonAPI/DBus/DBusMainLoopContext.hpp b/include/CommonAPI/DBus/DBusMainLoopContext.hpp index 8cf9cf2..c048c90 100644 --- a/include/CommonAPI/DBus/DBusMainLoopContext.hpp +++ b/include/CommonAPI/DBus/DBusMainLoopContext.hpp @@ -12,11 +12,14 @@ #include <list> #include <memory> +#include <queue> #include <dbus/dbus.h> #include <CommonAPI/MainLoopContext.hpp> +#include <CommonAPI/DBus/DBusProxyConnection.hpp> + namespace CommonAPI { namespace DBus { @@ -35,9 +38,26 @@ class DBusDispatchSource: public DispatchSource { DBusConnection* dbusConnection_; }; +class DBusMessageWatch; +class DBusMessageDispatchSource: public DispatchSource { + public: + DBusMessageDispatchSource(DBusMessageWatch* watch); + virtual ~DBusMessageDispatchSource(); + + bool prepare(int64_t& timeout); + bool check(); + bool dispatch(); + + private: + DBusMessageWatch* watch_; + + std::mutex watchMutex_; +}; + class DBusWatch: public Watch { public: - DBusWatch(::DBusWatch* libdbusWatch, std::weak_ptr<MainLoopContext>& mainLoopContext); + DBusWatch(::DBusWatch* libdbusWatch, std::weak_ptr<MainLoopContext>& mainLoopContext, + std::weak_ptr<DBusConnection>& dbusConnection); bool isReadyToBeWatched(); void startWatching(); @@ -61,10 +81,81 @@ class DBusWatch: public Watch { std::vector<DispatchSource*> dependentDispatchSources_; std::weak_ptr<MainLoopContext> mainLoopContext_; + std::weak_ptr<DBusConnection> dbusConnection_; + +#ifdef WIN32 + HANDLE wsaEvent_; +#endif +}; + +class DBusMessageWatch : public Watch { +public: + + struct MsgQueueEntry { + MsgQueueEntry(DBusMessage _message) : + message_(_message) { } + DBusMessage message_; + + virtual void process(std::shared_ptr<DBusConnection> _connection) = 0; + virtual void clear(); + }; + + struct MsgReplyQueueEntry : MsgQueueEntry { + MsgReplyQueueEntry(DBusProxyConnection::DBusMessageReplyAsyncHandler* _replyAsyncHandler, + DBusMessage _reply) : + MsgQueueEntry(_reply), + replyAsyncHandler_(_replyAsyncHandler) { } + + DBusProxyConnection::DBusMessageReplyAsyncHandler* replyAsyncHandler_; + + void process(std::shared_ptr<DBusConnection> _connection); + void clear(); + }; + + DBusMessageWatch(std::shared_ptr<DBusConnection> _connection); + virtual ~DBusMessageWatch(); + + void dispatch(unsigned int eventFlags); + + const pollfd& getAssociatedFileDescriptor(); #ifdef WIN32 + const HANDLE& getAssociatedEvent(); +#endif + + const std::vector<DispatchSource*>& getDependentDispatchSources(); + + void addDependentDispatchSource(CommonAPI::DispatchSource* _dispatchSource); + + void removeDependentDispatchSource(CommonAPI::DispatchSource* _dispatchSource); + + void pushMsgQueue(std::shared_ptr<MsgQueueEntry> _queueEntry); + + void popMsgQueue(); + + std::shared_ptr<MsgQueueEntry> frontMsgQueue(); + + bool emptyMsgQueue(); + + void processMsgQueueEntry(std::shared_ptr<MsgQueueEntry> _queueEntry); + +private: + int pipeFileDescriptors_[2]; + + pollfd pollFileDescriptor_; + std::vector<CommonAPI::DispatchSource*> dependentDispatchSources_; + std::queue<std::shared_ptr<MsgQueueEntry>> msgQueue_; + + std::mutex msgQueueMutex_; + + std::weak_ptr<DBusConnection> connection_; + + const int pipeValue_; +#ifdef WIN32 HANDLE wsaEvent_; + OVERLAPPED ov; #endif + }; diff --git a/include/CommonAPI/DBus/DBusMessage.hpp b/include/CommonAPI/DBus/DBusMessage.hpp index 0519e9d..b005904 100644 --- a/include/CommonAPI/DBus/DBusMessage.hpp +++ b/include/CommonAPI/DBus/DBusMessage.hpp @@ -93,6 +93,8 @@ public: bool setBodyLength(const int bodyLength); bool setDestination(const char* destination); + void setSerial(const unsigned int serial) const; + private: ::DBusMessage *message_; diff --git a/include/CommonAPI/DBus/DBusObjectManager.hpp b/include/CommonAPI/DBus/DBusObjectManager.hpp index e2ec2c5..2d36aaf 100644 --- a/include/CommonAPI/DBus/DBusObjectManager.hpp +++ b/include/CommonAPI/DBus/DBusObjectManager.hpp @@ -50,8 +50,9 @@ class DBusObjectManager { COMMONAPI_EXPORT bool onFreedesktopPropertiesDBusMessage(const DBusMessage& callMessage); - typedef std::unordered_map<DBusInterfaceHandlerPath, std::shared_ptr<DBusInterfaceHandler>> DBusRegisteredObjectsTable; + typedef std::unordered_map<DBusInterfaceHandlerPath, std::vector<std::shared_ptr<DBusInterfaceHandler>>> DBusRegisteredObjectsTable; DBusRegisteredObjectsTable dbusRegisteredObjectsTable_; + COMMONAPI_EXPORT bool addToRegisteredObjectsTable(DBusInterfaceHandlerPath ifpath, std::shared_ptr<DBusInterfaceHandler> handler); std::shared_ptr<DBusObjectManagerStub> rootDBusObjectManagerStub_; diff --git a/include/CommonAPI/DBus/DBusObjectManagerStub.hpp b/include/CommonAPI/DBus/DBusObjectManagerStub.hpp index 6d88951..de8495d 100644 --- a/include/CommonAPI/DBus/DBusObjectManagerStub.hpp +++ b/include/CommonAPI/DBus/DBusObjectManagerStub.hpp @@ -112,7 +112,7 @@ public: std::string dbusObjectPath_; std::weak_ptr<DBusProxyConnection> dbusConnection_; - typedef std::unordered_map<std::string, std::shared_ptr<DBusStubAdapter>> DBusInterfacesMap; + typedef std::unordered_map<std::string, std::vector<std::shared_ptr<DBusStubAdapter>>> DBusInterfacesMap; typedef std::unordered_map<std::string, DBusInterfacesMap> DBusObjectPathsMap; DBusObjectPathsMap registeredDBusObjectPathsMap_; diff --git a/include/CommonAPI/DBus/DBusOutputStream.hpp b/include/CommonAPI/DBus/DBusOutputStream.hpp index b99c9c8..6814430 100644 --- a/include/CommonAPI/DBus/DBusOutputStream.hpp +++ b/include/CommonAPI/DBus/DBusOutputStream.hpp @@ -10,7 +10,6 @@ #ifndef COMMONAPI_DBUS_DBUSOUTPUTSTREAM_HPP_ #define COMMONAPI_DBUS_DBUSOUTPUTSTREAM_HPP_ -#include <cassert> #include <cstring> #include <memory> #include <stack> @@ -231,6 +230,14 @@ public: return (*this); } + COMMONAPI_EXPORT OutputStream &writeValue(const std::vector<uint8_t> &_value, + const EmptyDeployment *_depl) { + (void)_depl; + align(sizeof(uint32_t)); + writeByteBuffer(_value.data(), static_cast<uint32_t>(_value.size())); + return (*this); + } + template<class Deployment_, typename ElementType_> COMMONAPI_EXPORT OutputStream &writeValue(const std::vector<ElementType_> &_value, const Deployment_ *_depl) { @@ -405,13 +412,17 @@ private: template<typename Type_> COMMONAPI_EXPORT void _writeValueAt(size_t _position, const Type_ &_value) { - assert(_position + sizeof(Type_) <= payload_.size()); + if ((_position + sizeof(Type_)) > payload_.size()) { + COMMONAPI_ERROR(std::string(__FUNCTION__) + ": payload size ", payload_.size(), " too small ", (_position + sizeof(Type_))); + } _writeRawAt(reinterpret_cast<const char *>(&_value), sizeof(Type_), _position); } COMMONAPI_EXPORT DBusOutputStream &writeString(const char *_data, const uint32_t &_length); + COMMONAPI_EXPORT DBusOutputStream &writeByteBuffer(const uint8_t *_date, const uint32_t &_length); + /** * Takes sizeInByte characters, starting from the character which val points to, and stores them for later writing. * When calling flush(), all values that were written to this stream are copied into the payload of the #DBusMessage. diff --git a/include/CommonAPI/DBus/DBusProxy.hpp b/include/CommonAPI/DBus/DBusProxy.hpp index 04f2ca9..c8a57bc 100644 --- a/include/CommonAPI/DBus/DBusProxy.hpp +++ b/include/CommonAPI/DBus/DBusProxy.hpp @@ -36,8 +36,9 @@ class DBusProxyStatusEvent }; -class DBusProxy - : public DBusProxyBase { +class COMMONAPI_EXPORT_CLASS_EXPLICIT DBusProxy + : public DBusProxyBase, + public std::enable_shared_from_this<DBusProxy> { public: COMMONAPI_EXPORT DBusProxy(const DBusAddress &_address, const std::shared_ptr<DBusProxyConnection> &_connection); @@ -48,14 +49,20 @@ public: COMMONAPI_EXPORT virtual bool isAvailable() const; COMMONAPI_EXPORT virtual bool isAvailableBlocking() const; + COMMONAPI_EXPORT virtual std::future<AvailabilityStatus> isAvailableAsync( + isAvailableAsyncCallback _callback, + const CallInfo *_info) const; - COMMONAPI_EXPORT DBusProxyConnection::DBusSignalHandlerToken subscribeForSelectiveBroadcastOnConnection( - bool& subscriptionAccepted, + COMMONAPI_EXPORT void subscribeForSelectiveBroadcastOnConnection( const std::string& objectPath, const std::string& interfaceName, const std::string& interfaceMemberName, const std::string& interfaceMemberSignature, - DBusProxyConnection::DBusSignalHandler* dbusSignalHandler); + DBusProxyConnection::DBusSignalHandler* dbusSignalHandler, + uint32_t tag); + + COMMONAPI_EXPORT void insertSelectiveSubscription(const std::string& interfaceMemberName, + DBusProxyConnection::DBusSignalHandler* dbusSignalHandler, uint32_t tag); COMMONAPI_EXPORT void unsubscribeFromSelectiveBroadcast(const std::string& eventName, DBusProxyConnection::DBusSignalHandlerToken subscription, const DBusProxyConnection::DBusSignalHandler* dbusSignalHandler); @@ -119,10 +126,11 @@ private: const uint32_t tag); COMMONAPI_EXPORT void addSignalMemberHandlerToQueue(SignalMemberHandlerTuple& _signalMemberHandler); + COMMONAPI_EXPORT void availabilityTimeoutThreadHandler() const; + DBusProxyStatusEvent dbusProxyStatusEvent_; DBusServiceRegistry::DBusServiceSubscription dbusServiceRegistrySubscription_; AvailabilityStatus availabilityStatus_; - mutable std::mutex availabilityStatusMutex_; DBusReadonlyAttribute<InterfaceVersionAttribute> interfaceVersionAttribute_; @@ -132,11 +140,22 @@ private: mutable std::condition_variable availabilityCondition_; std::list<SignalMemberHandlerTuple> signalMemberHandlerQueue_; - CallInfo signalMemberHandlerInfo_; mutable std::mutex signalMemberHandlerQueueMutex_; - std::map<std::string, DBusProxyConnection::DBusSignalHandler*> selectiveBroadcastHandlers; + std::map<std::string, std::pair<DBusProxyConnection::DBusSignalHandler*, uint32_t>> selectiveBroadcastHandlers; mutable std::mutex selectiveBroadcastHandlersMutex_; + + mutable std::shared_ptr<std::thread> availabilityTimeoutThread_; + mutable std::mutex availabilityTimeoutThreadMutex_; + mutable std::mutex timeoutsMutex_; + mutable std::condition_variable availabilityTimeoutCondition_; + + typedef std::tuple< + std::chrono::time_point<std::chrono::high_resolution_clock>, + isAvailableAsyncCallback, + std::promise<AvailabilityStatus> + > AvailabilityTimeout_t; + mutable std::list<AvailabilityTimeout_t> timeouts_; }; diff --git a/include/CommonAPI/DBus/DBusProxyAsyncCallbackHandler.hpp b/include/CommonAPI/DBus/DBusProxyAsyncCallbackHandler.hpp index 0a0ee56..c36ccb1 100644 --- a/include/CommonAPI/DBus/DBusProxyAsyncCallbackHandler.hpp +++ b/include/CommonAPI/DBus/DBusProxyAsyncCallbackHandler.hpp @@ -22,21 +22,31 @@ namespace CommonAPI { namespace DBus { -template<typename ... ArgTypes_> +template<typename DelegateObjectType_, typename ... ArgTypes_> class DBusProxyAsyncCallbackHandler: public DBusProxyConnection::DBusMessageReplyAsyncHandler { public: - typedef std::function<void(CallStatus, ArgTypes_...)> FunctionType; + + struct Delegate { + typedef std::function<void(CallStatus, ArgTypes_...)> FunctionType; + + Delegate(std::shared_ptr<DelegateObjectType_> object, FunctionType function) : + function_(std::move(function)) { + object_ = object; + } + std::weak_ptr<DelegateObjectType_> object_; + FunctionType function_; + }; static std::unique_ptr<DBusProxyConnection::DBusMessageReplyAsyncHandler> create( - FunctionType&& callback, std::tuple<ArgTypes_...> args) { + Delegate& delegate, std::tuple<ArgTypes_...> args) { return std::unique_ptr<DBusProxyConnection::DBusMessageReplyAsyncHandler>( - new DBusProxyAsyncCallbackHandler(std::move(callback), args)); + new DBusProxyAsyncCallbackHandler<DelegateObjectType_, ArgTypes_...>(std::move(delegate), args)); } DBusProxyAsyncCallbackHandler() = delete; - DBusProxyAsyncCallbackHandler(FunctionType&& callback, std::tuple<ArgTypes_...> args) - : callback_(std::move(callback)), + DBusProxyAsyncCallbackHandler(Delegate&& delegate, std::tuple<ArgTypes_...> args) + : delegate_(std::move(delegate)), args_(args), executionStarted_(false), executionFinished_(false), @@ -67,7 +77,7 @@ class DBusProxyAsyncCallbackHandler: virtual void setExecutionFinished() { executionFinished_ = true; // free assigned std::function<> immediately - callback_ = [](CallStatus, ArgTypes_...) {}; + delegate_.function_ = [](CallStatus, ArgTypes_...) {}; } virtual bool getExecutionFinished() { @@ -124,12 +134,15 @@ class DBusProxyAsyncCallbackHandler: } } - callback_(callStatus, std::move(std::get<ArgIndices_>(argTuple))...); + //check if object is expired + if(!delegate_.object_.expired()) + delegate_.function_(callStatus, std::move(std::get<ArgIndices_>(argTuple))...); + return callStatus; } std::promise<CallStatus> promise_; - FunctionType callback_; + Delegate delegate_; std::tuple<ArgTypes_...> args_; bool executionStarted_; bool executionFinished_; diff --git a/include/CommonAPI/DBus/DBusProxyAsyncSignalMemberCallbackHandler.hpp b/include/CommonAPI/DBus/DBusProxyAsyncSignalMemberCallbackHandler.hpp index f6d7791..11cb354 100644 --- a/include/CommonAPI/DBus/DBusProxyAsyncSignalMemberCallbackHandler.hpp +++ b/include/CommonAPI/DBus/DBusProxyAsyncSignalMemberCallbackHandler.hpp @@ -21,22 +21,33 @@ namespace CommonAPI { namespace DBus { +template <typename DelegateObjectType_> class DBusProxyAsyncSignalMemberCallbackHandler: public DBusProxyConnection::DBusMessageReplyAsyncHandler { public: - typedef std::function<void(CallStatus, DBusMessage, DBusProxyConnection::DBusSignalHandler*, int)> FunctionType; + + struct Delegate { + typedef std::function<void(CallStatus, DBusMessage, DBusProxyConnection::DBusSignalHandler*, uint32_t)> FunctionType; + + Delegate(std::shared_ptr<DelegateObjectType_> object, FunctionType function) : + function_(std::move(function)) { + object_ = object; + } + std::weak_ptr<DelegateObjectType_> object_; + FunctionType function_; + }; static std::unique_ptr<DBusProxyConnection::DBusMessageReplyAsyncHandler> create( - FunctionType& callback, DBusProxyConnection::DBusSignalHandler* dbusSignalHandler, - const int tag) { + Delegate& delegate, DBusProxyConnection::DBusSignalHandler* dbusSignalHandler, + const uint32_t tag) { return std::unique_ptr<DBusProxyConnection::DBusMessageReplyAsyncHandler>( - new DBusProxyAsyncSignalMemberCallbackHandler(std::move(callback), dbusSignalHandler, tag)); + new DBusProxyAsyncSignalMemberCallbackHandler<DelegateObjectType_>(std::move(delegate), dbusSignalHandler, tag)); } DBusProxyAsyncSignalMemberCallbackHandler() = delete; - DBusProxyAsyncSignalMemberCallbackHandler(FunctionType&& callback, + DBusProxyAsyncSignalMemberCallbackHandler(Delegate&& delegate, DBusProxyConnection::DBusSignalHandler* dbusSignalHandler, - const int tag): - callback_(std::move(callback)), dbusSignalHandler_(dbusSignalHandler), tag_(tag), + const uint32_t tag): + delegate_(std::move(delegate)), dbusSignalHandler_(dbusSignalHandler), tag_(tag), executionStarted_(false), executionFinished_(false), timeoutOccurred_(false), hasToBeDeleted_(false) { } @@ -94,14 +105,17 @@ class DBusProxyAsyncSignalMemberCallbackHandler: public DBusProxyConnection::DBu inline CallStatus handleDBusMessageReply(const CallStatus dbusMessageCallStatus, const DBusMessage& dbusMessage) const { CallStatus callStatus = dbusMessageCallStatus; - callback_(callStatus, dbusMessage, dbusSignalHandler_, tag_); + //check if object is expired + if(!delegate_.object_.expired()) + delegate_.function_(callStatus, dbusMessage, dbusSignalHandler_, tag_); + return callStatus; } std::promise<CallStatus> promise_; - const FunctionType callback_; + const Delegate delegate_; DBusProxyConnection::DBusSignalHandler* dbusSignalHandler_; - const int tag_; + const uint32_t tag_; bool executionStarted_; bool executionFinished_; bool timeoutOccurred_; diff --git a/include/CommonAPI/DBus/DBusProxyBase.hpp b/include/CommonAPI/DBus/DBusProxyBase.hpp index 4657bbf..2193ca7 100644 --- a/include/CommonAPI/DBus/DBusProxyBase.hpp +++ b/include/CommonAPI/DBus/DBusProxyBase.hpp @@ -26,7 +26,7 @@ namespace DBus { class DBusAddress; -class DBusProxyBase +class COMMONAPI_EXPORT_CLASS_EXPLICIT DBusProxyBase : public virtual CommonAPI::Proxy { public: COMMONAPI_EXPORT DBusProxyBase(const DBusAddress &_address, @@ -39,6 +39,11 @@ public: COMMONAPI_EXPORT DBusMessage createMethodCall(const std::string &_method, const std::string &_signature = "") const; + typedef std::function<void(const AvailabilityStatus, const Timeout_t remaining)> isAvailableAsyncCallback; + COMMONAPI_EXPORT virtual std::future<AvailabilityStatus> isAvailableAsync( + isAvailableAsyncCallback _callback, + const CallInfo *_info) const = 0; + COMMONAPI_EXPORT virtual DBusProxyConnection::DBusSignalHandlerToken addSignalMemberHandler( const std::string &objectPath, const std::string &interfaceName, diff --git a/include/CommonAPI/DBus/DBusProxyConnection.hpp b/include/CommonAPI/DBus/DBusProxyConnection.hpp index bec052b..8f7a1c8 100644 --- a/include/CommonAPI/DBus/DBusProxyConnection.hpp +++ b/include/CommonAPI/DBus/DBusProxyConnection.hpp @@ -57,19 +57,22 @@ class DBusProxyConnection { virtual void unlock() = 0; }; + class DBusSignalHandler; + + // objectPath, interfaceName, interfaceMemberName, interfaceMemberSignature + typedef std::tuple<std::string, std::string, std::string, std::string> DBusSignalHandlerPath; + typedef std::unordered_map<DBusSignalHandlerPath, std::pair<std::shared_ptr<std::recursive_mutex>, std::set<DBusSignalHandler* >>> DBusSignalHandlerTable; + typedef DBusSignalHandlerPath DBusSignalHandlerToken; + class DBusSignalHandler { public: virtual ~DBusSignalHandler() {} virtual void onSignalDBusMessage(const DBusMessage&) = 0; virtual void onInitialValueSignalDBusMessage(const DBusMessage&, const uint32_t) {}; - virtual void onError(const CommonAPI::CallStatus status) { (void) status; }; + virtual void onSpecificError(const CommonAPI::CallStatus, const uint32_t ) {}; + virtual void setSubscriptionToken(const DBusSignalHandlerToken, const uint32_t) {}; }; - // objectPath, interfaceName, interfaceMemberName, interfaceMemberSignature - typedef std::tuple<std::string, std::string, std::string, std::string> DBusSignalHandlerPath; - typedef std::unordered_map<DBusSignalHandlerPath, std::pair<std::shared_ptr<std::recursive_mutex>, std::set<DBusSignalHandler* >>> DBusSignalHandlerTable; - typedef DBusSignalHandlerPath DBusSignalHandlerToken; - typedef Event<AvailabilityStatus> ConnectionStatusEvent; virtual ~DBusProxyConnection() {} @@ -98,13 +101,13 @@ class DBusProxyConnection { DBusSignalHandler* dbusSignalHandler, const bool justAddFilter = false) = 0; - virtual DBusSignalHandlerToken subscribeForSelectiveBroadcast(bool& subscriptionAccepted, - const std::string& objectPath, + virtual void subscribeForSelectiveBroadcast(const std::string& objectPath, const std::string& interfaceName, const std::string& interfaceMemberName, const std::string& interfaceMemberSignature, DBusSignalHandler* dbusSignalHandler, - DBusProxy* callingProxy) = 0; + DBusProxy* callingProxy, + uint32_t tag) = 0; virtual void unsubscribeFromSelectiveBroadcast(const std::string& eventName, DBusProxyConnection::DBusSignalHandlerToken subscription, @@ -134,7 +137,11 @@ class DBusProxyConnection { virtual bool hasDispatchThread() = 0; - virtual bool sendPendingSelectiveSubscription(DBusProxy* proxy, std::string methodName) = 0; + virtual void sendPendingSelectiveSubscription(DBusProxy* proxy, std::string methodName, + DBusSignalHandler* dbusSignalHandler, uint32_t tag) = 0; + + virtual void pushDBusMessageReply(const DBusMessage& reply, + std::unique_ptr<DBusMessageReplyAsyncHandler> dbusMessageReplyAsyncHandler) = 0; }; } // namespace DBus diff --git a/include/CommonAPI/DBus/DBusProxyHelper.hpp b/include/CommonAPI/DBus/DBusProxyHelper.hpp index ef468ee..cb5b942 100644 --- a/include/CommonAPI/DBus/DBusProxyHelper.hpp +++ b/include/CommonAPI/DBus/DBusProxyHelper.hpp @@ -172,13 +172,13 @@ struct DBusProxyHelper<In_<DBusInputStream, DBusOutputStream, InArgs_...>, } } - template <typename DBusProxy_ = DBusProxy, typename AsyncCallback_> + template <typename DBusProxy_ = DBusProxy, typename DelegateFunction_> static std::future<CallStatus> callMethodAsync( - const DBusProxy_ &_proxy, + DBusProxy_ &_proxy, DBusMessage &_message, const CommonAPI::CallInfo *_info, const InArgs_&... _in, - AsyncCallback_ _callback, + DelegateFunction_ _function, std::tuple<OutArgs_...> _out) { if (sizeof...(InArgs_) > 0) { DBusOutputStream output(_message); @@ -193,51 +193,75 @@ struct DBusProxyHelper<In_<DBusInputStream, DBusOutputStream, InArgs_...>, output.flush(); } - return _proxy.getDBusConnection()->sendDBusMessageWithReplyAsync( - _message, - DBusProxyAsyncCallbackHandler< - OutArgs_... - >::create(std::move(_callback), _out), - _info); + typename DBusProxyAsyncCallbackHandler< + DBusProxy, OutArgs_... + >::Delegate delegate(_proxy.shared_from_this(), _function); + auto dbusMessageReplyAsyncHandler = DBusProxyAsyncCallbackHandler< + DBusProxy, OutArgs_... + >::create(delegate, _out).release(); + + if(_proxy.isAvailable()) { + return _proxy.getDBusConnection()->sendDBusMessageWithReplyAsync( + _message, + std::unique_ptr<DBusProxyConnection::DBusMessageReplyAsyncHandler>(dbusMessageReplyAsyncHandler), + _info); + } else { + //async isAvailable call with timeout + _proxy.isAvailableAsync([&_proxy, _message, _info, + _out, dbusMessageReplyAsyncHandler, _function]( + const AvailabilityStatus _status, + const Timeout_t remaining) { + if(_status == AvailabilityStatus::AVAILABLE) { + //create new call info with remaining timeout. Minimal timeout is 100 ms. + Timeout_t newTimeout = remaining; + if(remaining < 100) + newTimeout = 100; + CallInfo newInfo(newTimeout); + _proxy.getDBusConnection()->sendDBusMessageWithReplyAsync( + _message, + std::unique_ptr<DBusProxyConnection::DBusMessageReplyAsyncHandler>(dbusMessageReplyAsyncHandler), + &newInfo); + } else { + //create error message and push it directly to the connection + unsigned int dummySerial = 999; + _message.setSerial(dummySerial); //set dummy serial + DBusMessage errorMessage = _message.createMethodError(DBUS_ERROR_UNKNOWN_METHOD); + _proxy.getDBusConnection()->pushDBusMessageReply(errorMessage, + std::unique_ptr<DBusProxyConnection::DBusMessageReplyAsyncHandler>(dbusMessageReplyAsyncHandler)); + } + }, _info); + return dbusMessageReplyAsyncHandler->getFuture(); + } } - template <typename DBusProxy_ = DBusProxy, typename AsyncCallback_> + template <typename DBusProxy_ = DBusProxy, typename DelegateFunction_> static std::future<CallStatus> callMethodAsync( - const DBusProxy_ &_proxy, + DBusProxy_ &_proxy, const DBusAddress &_address, const std::string &_method, const std::string &_signature, const CommonAPI::CallInfo *_info, const InArgs_&... _in, - AsyncCallback_ _callback, + DelegateFunction_ _function, std::tuple<OutArgs_...> _out) { #ifndef WIN32 static std::mutex callMethodAsync_mutex_; #endif std::lock_guard<std::mutex> lock(callMethodAsync_mutex_); - if (_proxy.isAvailable()) { - DBusMessage message = DBusMessage::createMethodCall(_address, _method, _signature); - return callMethodAsync(_proxy, message, _info, _in..., _callback, _out); - } else { - CallStatus status = CallStatus::NOT_AVAILABLE; - callCallbackOnNotAvailable(_callback, typename make_sequence<sizeof...(OutArgs_)>::type(), _out); - - std::promise<CallStatus> promise; - promise.set_value(status); - return promise.get_future(); - } + DBusMessage message = DBusMessage::createMethodCall(_address, _method, _signature); + return callMethodAsync(_proxy, message, _info, _in..., _function, _out); } - template <typename DBusProxy_ = DBusProxy, typename AsyncCallback_> + template <typename DBusProxy_ = DBusProxy, typename DelegateFunction_> static std::future<CallStatus> callMethodAsync( - const DBusProxy_ &_proxy, + DBusProxy_ &_proxy, const std::string &_interface, const std::string &_method, const std::string &_signature, const CommonAPI::CallInfo *_info, const InArgs_&... _in, - AsyncCallback_ _callback, + DelegateFunction_ _function, std::tuple<OutArgs_...> _out) { DBusAddress itsAddress(_proxy.getDBusAddress()); itsAddress.setInterface(_interface); @@ -245,43 +269,34 @@ struct DBusProxyHelper<In_<DBusInputStream, DBusOutputStream, InArgs_...>, _proxy, itsAddress, _method, _signature, _info, - _in..., _callback, _out); + _in..., _function, + _out); } - template <typename DBusProxy_ = DBusProxy, typename AsyncCallback_> + template <typename DBusProxy_ = DBusProxy, typename DelegateFunction_> static std::future<CallStatus> callMethodAsync( - const DBusProxy_ &_proxy, + DBusProxy_ &_proxy, const std::string &_method, const std::string &_signature, const CommonAPI::CallInfo *_info, const InArgs_&... _in, - AsyncCallback_ _callback, + DelegateFunction_ _function, std::tuple<OutArgs_...> _out) { #ifndef WIN32 static std::mutex callMethodAsync_mutex_; #endif std::lock_guard<std::mutex> lock(callMethodAsync_mutex_); - if (_proxy.isAvailable()) { - DBusMessage message = _proxy.createMethodCall(_method, _signature); - return callMethodAsync(_proxy, message, _info, _in..., _callback, _out); - } else { - callCallbackOnNotAvailable( - _callback, typename make_sequence<sizeof...(OutArgs_)>::type(), _out); - - CallStatus status = CallStatus::NOT_AVAILABLE; - std::promise<CallStatus> promise; - promise.set_value(status); - return promise.get_future(); - } + DBusMessage message = _proxy.createMethodCall(_method, _signature); + return callMethodAsync(_proxy, message, _info, _in..., _function, _out); } template <int... ArgIndices_> static void callCallbackOnNotAvailable(std::function<void(CallStatus, OutArgs_&...)> _callback, index_sequence<ArgIndices_...>, std::tuple<OutArgs_...> _out) { const CallStatus status(CallStatus::NOT_AVAILABLE); - _callback(status, std::get<ArgIndices_>(_out)...); - (void)_out; + _callback(status, std::get<ArgIndices_>(_out)...); + (void)_out; } }; diff --git a/include/CommonAPI/DBus/DBusProxyManager.hpp b/include/CommonAPI/DBus/DBusProxyManager.hpp index 9540ead..ff28a26 100644 --- a/include/CommonAPI/DBus/DBusProxyManager.hpp +++ b/include/CommonAPI/DBus/DBusProxyManager.hpp @@ -26,7 +26,7 @@ namespace CommonAPI { namespace DBus { -class DBusProxyManager: public ProxyManager { +class COMMONAPI_EXPORT_CLASS_EXPLICIT DBusProxyManager: public ProxyManager { public: COMMONAPI_EXPORT DBusProxyManager(DBusProxy &_proxy, const std::string &_interfaceName); diff --git a/include/CommonAPI/DBus/DBusSelectiveEvent.hpp b/include/CommonAPI/DBus/DBusSelectiveEvent.hpp index 961063a..627a17b 100644 --- a/include/CommonAPI/DBus/DBusSelectiveEvent.hpp +++ b/include/CommonAPI/DBus/DBusSelectiveEvent.hpp @@ -36,21 +36,24 @@ public: virtual ~DBusSelectiveEvent() {} - virtual void onError(const CommonAPI::CallStatus status) { - this->notifyError(status); + virtual void onSpecificError(const CommonAPI::CallStatus status, uint32_t tag) { + this->notifySpecificError(tag, status); + } + + virtual void setSubscriptionToken(const DBusProxyConnection::DBusSignalHandlerToken _subscriptionToken, uint32_t tag) { + this->subscription_ = _subscriptionToken; + static_cast<DBusProxy&>(this->proxy_).insertSelectiveSubscription(this->name_, this, tag); } protected: void onFirstListenerAdded(const Listener &) { - bool success; - this->subscription_ - = static_cast<DBusProxy&>(this->proxy_).subscribeForSelectiveBroadcastOnConnection( - success, this->path_, this->interface_, this->name_, this->signature_, this); - - if (success == false) { - // Call error listener with an error code - this->notifyError(CommonAPI::CallStatus::SUBSCRIPTION_REFUSED); - } + + } + + void onListenerAdded(const Listener &_listener, const uint32_t subscription) { + (void) _listener; + static_cast<DBusProxy&>(this->proxy_).subscribeForSelectiveBroadcastOnConnection( + this->path_, this->interface_, this->name_, this->signature_, this, subscription); } void onLastListenerRemoved(const Listener &) { diff --git a/include/CommonAPI/DBus/DBusServiceRegistry.hpp b/include/CommonAPI/DBus/DBusServiceRegistry.hpp index 584c47a..17e7139 100644 --- a/include/CommonAPI/DBus/DBusServiceRegistry.hpp +++ b/include/CommonAPI/DBus/DBusServiceRegistry.hpp @@ -68,6 +68,7 @@ class DBusServiceRegistry: public std::enable_shared_from_this<DBusServiceRegist typedef DBusManagedInterfaceListenerList::iterator DBusManagedInterfaceSubscription; static std::shared_ptr<DBusServiceRegistry> get(std::shared_ptr<DBusProxyConnection> _connection); + static void remove(std::shared_ptr<DBusProxyConnection> _connection); DBusServiceRegistry(std::shared_ptr<DBusProxyConnection> dbusProxyConnection); @@ -158,6 +159,7 @@ class DBusServiceRegistry: public std::enable_shared_from_this<DBusServiceRegist : referenceCount(other.referenceCount), state(other.state), promiseOnResolve(std::move(other.promiseOnResolve)), + futureOnResolve(std::move(other.futureOnResolve)), serviceName(std::move(other.serviceName)), dbusInterfaceNamesCache(std::move(other.dbusInterfaceNamesCache)){ } @@ -167,6 +169,7 @@ class DBusServiceRegistry: public std::enable_shared_from_this<DBusServiceRegist size_t referenceCount; DBusRecordState state; std::promise<DBusRecordState> promiseOnResolve; + std::shared_future<DBusRecordState> futureOnResolve; std::string serviceName; std::unordered_set<std::string> dbusInterfaceNamesCache; diff --git a/include/CommonAPI/DBus/DBusStubAdapter.hpp b/include/CommonAPI/DBus/DBusStubAdapter.hpp index b2bea37..710277b 100644 --- a/include/CommonAPI/DBus/DBusStubAdapter.hpp +++ b/include/CommonAPI/DBus/DBusStubAdapter.hpp @@ -22,7 +22,7 @@ namespace DBus { class DBusProxyConnection; -class DBusStubAdapter +class COMMONAPI_EXPORT_CLASS_EXPLICIT DBusStubAdapter : virtual public CommonAPI::StubAdapter, public DBusInterfaceHandler { public: diff --git a/include/CommonAPI/DBus/DBusStubAdapterHelper.hpp b/include/CommonAPI/DBus/DBusStubAdapterHelper.hpp index 0084360..42d7301 100644 --- a/include/CommonAPI/DBus/DBusStubAdapterHelper.hpp +++ b/include/CommonAPI/DBus/DBusStubAdapterHelper.hpp @@ -108,8 +108,12 @@ class DBusStubAdapterHelper: public virtual DBusStubAdapter { const char* interfaceMemberName = dbusMessage.getMember(); const char* interfaceMemberSignature = dbusMessage.getSignature(); - assert(interfaceMemberName); - assert(interfaceMemberSignature); + if (NULL == interfaceMemberName) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " member empty"); + } + if (NULL == interfaceMemberSignature) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " signature empty"); + } DBusInterfaceMemberPath dbusInterfaceMemberPath(interfaceMemberName, interfaceMemberSignature); auto findIterator = getStubDispatcherTable().find(dbusInterfaceMemberPath); @@ -160,8 +164,12 @@ class DBusStubAdapterHelper: public virtual DBusStubAdapter { } StubDispatcher* getterDispatcher = static_cast<StubDispatcher*>(attributeDispatcherIterator->second.getter); - assert(getterDispatcher != NULL); // all attributes have at least a getter - return (getterDispatcher->dispatchDBusMessage(_message, stub_, *this)); + if (NULL == getterDispatcher) { // all attributes have at least a getter + COMMONAPI_ERROR(std::string(__FUNCTION__), "getterDispatcher == NULL"); + return false; + } else { + return (getterDispatcher->dispatchDBusMessage(_message, stub_, *this)); + } } bool handleFreedesktopSet(const DBusMessage& dbusMessage, DBusInputStream& dbusInputStream) { @@ -206,10 +214,14 @@ class DBusStubAdapterHelper: public virtual DBusStubAdapter { //To prevent the destruction of the stub whilst still handling a message if (stub_) { StubDispatcher* getterDispatcher = static_cast<StubDispatcher*>(attributeDispatcherIterator->second.getter); - assert(getterDispatcher != NULL); // all attributes have at least a getter - dbusOutputStream.align(8); - dbusOutputStream << attributeDispatcherIterator->first; - getterDispatcher->appendGetAllReply(dbusMessage, stub_, *this, dbusOutputStream); + if (NULL == getterDispatcher) { // all attributes have at least a getter + COMMONAPI_ERROR(std::string(__FUNCTION__), "getterDispatcher == NULL"); + break; + } else { + dbusOutputStream.align(8); + dbusOutputStream << attributeDispatcherIterator->first; + getterDispatcher->appendGetAllReply(dbusMessage, stub_, *this, dbusOutputStream); + } } } @@ -463,9 +475,14 @@ private: } output.flush(); } - bool isSuccessful = connection_->sendDBusMessage(reply->second); - pending_.erase(_call); - return isSuccessful; + if (std::shared_ptr<DBusProxyConnection> connection = connection_.lock()) { + bool isSuccessful = connection->sendDBusMessage(reply->second); + pending_.erase(_call); + return isSuccessful; + } + else { + return false; + } } return false; } @@ -479,7 +496,7 @@ private: std::map<CommonAPI::CallId_t, DBusMessage> pending_; std::mutex mutex_; // protects pending_ - std::shared_ptr<DBusProxyConnection> connection_; + std::weak_ptr<DBusProxyConnection> connection_; }; template< class, class, class, class > diff --git a/include/murmurhash/MurmurHash3.h b/include/murmurhash/MurmurHash3.h index 54e9d3f..a7e45a7 100644 --- a/include/murmurhash/MurmurHash3.h +++ b/include/murmurhash/MurmurHash3.h @@ -8,9 +8,9 @@ //----------------------------------------------------------------------------- // Platform-specific functions and macros -// Microsoft Visual Studio +// Microsoft Visual Studio before VS2010 -#if defined(_MSC_VER) +#if defined(_MSC_VER) && (_MSC_VER < 1600) typedef unsigned char uint8_t; typedef unsigned long uint32_t; @@ -18,11 +18,11 @@ typedef unsigned __int64 uint64_t; // Other compilers -#else // defined(_MSC_VER) +#else // defined(_MSC_VER) && (_MSC_VER < 1600) #include <stdint.h> -#endif // !defined(_MSC_VER) +#endif // defined(_MSC_VER) && (_MSC_VER < 1600) //----------------------------------------------------------------------------- |