From 9a4f15f3ada99a420fe323b1fbb5a51e6c3d8351 Mon Sep 17 00:00:00 2001 From: sebaszm <45654185+sebaszm@users.noreply.github.com> Date: Wed, 17 Apr 2024 08:41:15 +0200 Subject: [PATCH] [JSONRPC] Add IConnectionServer to IShell (#1561) * [JSONRPC] Add IJSONRPCLink to IShell * [JSONRPC] Unify context and index to one template set * Omit proxystubs for IJSONRPCLink * Unregister notification if dropped channel removed all observers * Remove assert * Remove COMLink and JSONRPCLink accessors * ChannelClosed is private * Restore assert on Register * Report initial set on Register * Don't limit on JSONRPC anymore --------- Co-authored-by: Pierre Wielders --- Source/WPEFramework/PluginServer.cpp | 11 +- Source/WPEFramework/PluginServer.h | 145 ++++++++++++++++++--------- Source/com/Ids.h | 32 +++--- Source/core/JSONRPC.h | 111 ++++++++++---------- Source/plugins/IShell.h | 60 ++++++++--- Source/plugins/JSONRPC.cpp | 4 + Source/plugins/JSONRPC.h | 104 ++++++++++++++----- Source/plugins/Shell.cpp | 2 +- 8 files changed, 304 insertions(+), 165 deletions(-) diff --git a/Source/WPEFramework/PluginServer.cpp b/Source/WPEFramework/PluginServer.cpp index 630fd9a29..2ed4c1403 100644 --- a/Source/WPEFramework/PluginServer.cpp +++ b/Source/WPEFramework/PluginServer.cpp @@ -279,7 +279,7 @@ namespace PluginHost { _processAdministrator.Destroy(); } - /* virtual */ void* Server::Service::QueryInterface(const uint32_t id) + void* Server::Service::QueryInterface(const uint32_t id) /* override */ { void* result = nullptr; if (id == Core::IUnknown::ID) { @@ -290,8 +290,15 @@ namespace PluginHost { AddRef(); result = static_cast(this); } + else if (id == PluginHost::IShell::ICOMLink::ID) { + AddRef(); + result = static_cast(this); + } + else if (id == PluginHost::IShell::IConnectionServer::ID) { + AddRef(); + result = static_cast(this); + } else { - _pluginHandling.Lock(); if (_handler != nullptr) { diff --git a/Source/WPEFramework/PluginServer.h b/Source/WPEFramework/PluginServer.h index 4b4c05bb3..c7c86b393 100644 --- a/Source/WPEFramework/PluginServer.h +++ b/Source/WPEFramework/PluginServer.h @@ -311,7 +311,7 @@ namespace PluginHost { std::string _text; }; - class Service : public IShell::ICOMLink, public PluginHost::Service { + class Service : public IShell::ICOMLink, public IShell::IConnectionServer, public PluginHost::Service { public: enum mode { CONFIGURED, @@ -1216,10 +1216,6 @@ namespace PluginHost { result.ToString(info); return (Core::ERROR_NONE); } - // Use the base framework (webbridge) to start/stop processes and the service in side of the given binary. - IShell::ICOMLink* COMLink() override { - return (this); - } void* Instantiate(const RPC::Object& object, const uint32_t waitTime, uint32_t& sessionId) override { ASSERT(_connection == nullptr); @@ -1238,6 +1234,14 @@ namespace PluginHost { { _administrator.Unregister(sink); } + void Register(IShell::IConnectionServer::INotification* sink) override + { + _administrator.Register(sink); + } + void Unregister(const IShell::IConnectionServer::INotification* sink) override + { + _administrator.Unregister(sink); + } void Register(IShell::ICOMLink::INotification* sink) { _administrator.Register(sink); @@ -1251,10 +1255,6 @@ namespace PluginHost { return (_administrator.RemoteConnection(connectionId)); } - void Closed(const uint32_t /*id */) - { - } - // Methods to Activate and Deactivate the aggregated Plugin to this shell. // These are Blocking calls!!!!! Core::hresult Activate(const reason) override; @@ -1778,6 +1778,7 @@ namespace PluginHost { using Notifiers = std::vector; using RemoteInstantiators = std::unordered_map; using ShellNotifiers = std::vector< Exchange::Controller::IShells::INotification*>; + using ChannelObservers = std::vector; class Iterator { public: @@ -2567,6 +2568,8 @@ namespace PluginHost { , _subSystems(this) , _authenticationHandler(nullptr) , _configObserver(*this, server._config.PluginConfigPath()) + , _shellObservers() + , _channelObservers() { if (server._config.PluginConfigPath().empty() == true) { SYSLOG(Logging::Startup, (_T("Dynamic configs disabled."))); @@ -2818,6 +2821,40 @@ namespace PluginHost { { _processAdministrator.Unregister(sink); } + void Register(IShell::IConnectionServer::INotification* sink) + { + _notificationLock.Lock(); + + ASSERT(std::find(_channelObservers.begin(), _channelObservers.end(), sink) == _channelObservers.end()); + + _channelObservers.push_back(sink); + + ASSERT(sink != nullptr); + sink->AddRef(); + + _server.Visit([sink](const Channel& channel) { + if (channel.IsOpen() == true) { + sink->Opened(channel.Id()); + } + }); + + _notificationLock.Unlock(); + } + void Unregister(const IShell::IConnectionServer::INotification* sink) + { + _notificationLock.Lock(); + + ChannelObservers::iterator index(std::find(_channelObservers.begin(), _channelObservers.end(), sink)); + + ASSERT(index != _channelObservers.end()); + + if (index != _channelObservers.end()) { + (*index)->Release(); + _channelObservers.erase(index); + } + + _notificationLock.Unlock(); + } void Register(Exchange::Controller::IShells::INotification* sink) { _notificationLock.Lock(); @@ -2855,24 +2892,10 @@ namespace PluginHost { _notificationLock.Unlock(); } - RPC::IRemoteConnection* RemoteConnection(const uint32_t connectionId) { return (connectionId != 0 ? _processAdministrator.Connection(connectionId) : nullptr); } - void Closed(const uint32_t id) { - _adminLock.Lock(); - - // First stop all services running ... - Plugins::iterator index(_services.begin()); - - while (index != _services.end()) { - index->second->Closed(id); - ++index; - } - - _adminLock.Unlock(); - } inline Core::ProxyType Insert(const Plugin::Config& configuration, const Service::mode mode) { // Whatever plugin is needse, we at least have our Metadata plugin available (as the first entry :-). @@ -2889,7 +2912,6 @@ namespace PluginHost { return (newService); } - inline uint32_t Clone(const Core::ProxyType& originalShell, const string& newCallsign, Core::ProxyType& newService) { uint32_t result = Core::ERROR_GENERAL; @@ -2924,7 +2946,6 @@ namespace PluginHost { return (result); } - inline void Destroy(const string& callSign) { _adminLock.Lock(); @@ -3114,6 +3135,27 @@ namespace PluginHost { void Close(); void Destroy(); + void Opened(const uint32_t id) + { + _notificationLock.Lock(); + + for (auto& sink : _channelObservers) { + sink->Opened(id); + } + + _notificationLock.Unlock(); + } + void Closed(const uint32_t id) + { + _notificationLock.Lock(); + + for (auto& sink : _channelObservers) { + sink->Closed(id); + } + + _notificationLock.Unlock(); + } + private: void Dangling(const Core::IUnknown* source, const uint32_t interfaceId) { if (interfaceId == RPC::IRemoteConnection::INotification::ID) @@ -3249,6 +3291,7 @@ namespace PluginHost { IAuthenticate* _authenticationHandler; ConfigObserver _configObserver; ShellNotifiers _shellObservers; + ChannelObservers _channelObservers; }; // Connection handler is the listening socket and keeps track of all open @@ -4098,6 +4141,8 @@ namespace PluginHost { State(CLOSED, false); + _parent.Operational(Id(), false); + } else if (IsUpgrading() == true) { ASSERT(_service.IsValid() == false); @@ -4135,6 +4180,9 @@ namespace PluginHost { } } } + else if ((IsOpen() == true) && (IsWebSocket() == false)) { + _parent.Operational(Id(), true); + } } friend class Core::SocketServerType; @@ -4225,19 +4273,9 @@ namespace PluginHost { _job.Revoke(); // Start by closing the server thread.. - BaseClass::Close(waitTime); - // Kill all open connections, we are shutting down !!! - BaseClass::Iterator index(BaseClass::Clients()); - - while (index.Next() == true) { - // Oops nothing hapened for a long time, kill the connection - // give it 100ms to actually close, if not do it forcefully !! - index.Client()->Close(waitTime); - } - - // Cleanup the closed sockets we created.. - ValidateConnections(); + BaseClass::Close(waitTime); + BaseClass::Cleanup(); return (Core::ERROR_NONE); } @@ -4285,7 +4323,7 @@ namespace PluginHost { // Next Clean all Id's from JSONRPC nolonger available // // First check and clear, closed connections - ValidateConnections(); + BaseClass::Cleanup(); if (_connectionCheckTimer != 0) { // Now suspend those that have no activity. @@ -4310,17 +4348,6 @@ namespace PluginHost { _job.Reschedule(NextTick); } } - void ValidateConnections() { - BaseClass::Iterator index(BaseClass::Clients()); - - while (index.Next() == true) { - if (index.Client()->IsOpen() == false) { - TRACE(Activity, (_T("Client closed, that is reported closed"), index.Client()->Id())); - _parent.Services().Closed(index.Client()->Id()); - } - } - BaseClass::Cleanup(); - } private: Server& _parent; @@ -4445,6 +4472,26 @@ namespace PluginHost { return (infoBlob.Load()); } + void Visit(const std::function& handler) + { + ChannelMap::Iterator it = _connections.Clients(); + + while (it.Next() == true) { + handler(*it.Client()); + } + } + + private: + void Operational(const uint32_t id, const bool upAndRunning) + { + if (upAndRunning == true) { + Services().Opened(id); + } + else { + Services().Closed(id); + } + } + private: Core::ProxyType Controller() { diff --git a/Source/com/Ids.h b/Source/com/Ids.h index 050987bec..4bf0ae7e7 100644 --- a/Source/com/Ids.h +++ b/Source/com/Ids.h @@ -73,22 +73,24 @@ namespace RPC { ID_DISPATCHER_CALLBACK = (ID_OFFSET_INTERNAL + 0x002E), ID_SHELL = (ID_OFFSET_INTERNAL + 0x0030), - ID_STATECONTROL = (ID_OFFSET_INTERNAL + 0x0031), - ID_STATECONTROL_NOTIFICATION = (ID_OFFSET_INTERNAL + 0x0032), - ID_SUBSYSTEM = (ID_OFFSET_INTERNAL + 0x0033), - ID_SUBSYSTEM_NOTIFICATION = (ID_OFFSET_INTERNAL + 0x0034), - ID_SUBSYSTEM_INTERNET = (ID_OFFSET_INTERNAL + 0x0035), - ID_SUBSYSTEM_LOCATION = (ID_OFFSET_INTERNAL + 0x0036), - ID_SUBSYSTEM_IDENTIFIER = (ID_OFFSET_INTERNAL + 0x0037), - ID_SUBSYSTEM_TIME = (ID_OFFSET_INTERNAL + 0x0038), - ID_SUBSYSTEM_SECURITY = (ID_OFFSET_INTERNAL + 0x0039), - ID_SUBSYSTEM_PROVISIONING = (ID_OFFSET_INTERNAL + 0x003A), - ID_SUBSYSTEM_DECRYPTION = (ID_OFFSET_INTERNAL + 0x003B), - ID_REMOTE_INSTANTIATION = (ID_OFFSET_INTERNAL + 0x003C), - ID_COMREQUEST_NOTIFICATION = (ID_OFFSET_INTERNAL + 0x003D), - ID_SYSTEM_METADATA = (ID_OFFSET_INTERNAL + 0x003E), + ID_SHELL_COMLINK = (ID_OFFSET_INTERNAL + 0x0031), + ID_SHELL_CONNECTIONSERVER = (ID_OFFSET_INTERNAL + 0x0032), + ID_SHELL_CONNECTIONSERVER_NOTIFICATION = (ID_OFFSET_INTERNAL + 0x0033), + ID_STATECONTROL = (ID_OFFSET_INTERNAL + 0x0034), + ID_STATECONTROL_NOTIFICATION = (ID_OFFSET_INTERNAL + 0x0035), + ID_SUBSYSTEM = (ID_OFFSET_INTERNAL + 0x0036), + ID_SUBSYSTEM_NOTIFICATION = (ID_OFFSET_INTERNAL + 0x0037), + ID_SUBSYSTEM_INTERNET = (ID_OFFSET_INTERNAL + 0x0038), + ID_SUBSYSTEM_LOCATION = (ID_OFFSET_INTERNAL + 0x0039), + ID_SUBSYSTEM_IDENTIFIER = (ID_OFFSET_INTERNAL + 0x003A), + ID_SUBSYSTEM_TIME = (ID_OFFSET_INTERNAL + 0x003B), + ID_SUBSYSTEM_SECURITY = (ID_OFFSET_INTERNAL + 0x003C), + ID_SUBSYSTEM_PROVISIONING = (ID_OFFSET_INTERNAL + 0x003D), + ID_SUBSYSTEM_DECRYPTION = (ID_OFFSET_INTERNAL + 0x003E), + ID_REMOTE_INSTANTIATION = (ID_OFFSET_INTERNAL + 0x003F), + ID_SYSTEM_METADATA = (ID_OFFSET_INTERNAL + 0x0040), - ID_EXTERNAL_INTERFACE_OFFSET = (ID_OFFSET_INTERNAL + 0x0040), + ID_EXTERNAL_INTERFACE_OFFSET = (ID_OFFSET_INTERNAL + 0x0080), ID_EXTERNAL_QA_INTERFACE_OFFSET = (ID_OFFSET_INTERNAL + 0xA000) }; } diff --git a/Source/core/JSONRPC.h b/Source/core/JSONRPC.h index 974e8d135..72914243d 100644 --- a/Source/core/JSONRPC.h +++ b/Source/core/JSONRPC.h @@ -752,22 +752,12 @@ namespace Core { InternalProperty(::TemplateIntToType(), methodName, getMethod, setMethod, objectPtr); } template - typename std::enable_if::template argument<0>::type>::type>::type>::value, void>::type - Register(const string& methodName, const METHOD& method) + void Register(const string& methodName, const METHOD& method) { + using ARG0 = typename std::decay::template argument<0>::type>::type; + InternalRegister( - ::TemplateIntToType::template argument<0>::type, const Context&>::value>(), - ::TemplateIntToType::value>(), - ::TemplateIntToType::value>(), - methodName, - method); - } - template - typename std::enable_if::template argument<0>::type>::type>::type>::value, void>::type - Register(const string& methodName, const METHOD& method) - { - InternalRegisterWithIndex( - ::TemplateIntToType::template argument<0>::type, const Context&>::value>(), + ::TemplateIntToType::value | (std::is_same::value << 1)>(), ::TemplateIntToType::value>(), ::TemplateIntToType::value>(), methodName, @@ -776,8 +766,10 @@ namespace Core { template void Register(const string& methodName, const METHOD& method, REALOBJECT* objectPtr) { + using ARG0 = typename std::decay::template argument<0>::type>::type; + InternalRegister( - ::TemplateIntToType::template argument<0>::type, const Context&>::value>(), + ::TemplateIntToType::value | (std::is_same::value << 1)>(), ::TemplateIntToType::value>(), ::TemplateIntToType::value>(), methodName, @@ -1087,7 +1079,7 @@ namespace Core { Register(methodName, implementation); } template - void InternalRegisterWithIndex(const ::TemplateIntToType<0>&, const ::TemplateIntToType<0>&, const ::TemplateIntToType<1>&, const string& methodName, const METHOD& method) + void InternalRegister(const ::TemplateIntToType<2>&, const ::TemplateIntToType<0>&, const ::TemplateIntToType<1>&, const string& methodName, const METHOD& method) { std::function actualMethod = method; InvokeFunction implementation = [actualMethod](const Context&, const string& method, const string& parameters, string& result) -> uint32_t { @@ -1108,7 +1100,7 @@ namespace Core { Register(methodName, implementation); } template - void InternalRegisterWithIndex(const ::TemplateIntToType<0>&, const ::TemplateIntToType<1>&, const ::TemplateIntToType<0>&, const string& methodName, const METHOD& method) + void InternalRegister(const ::TemplateIntToType<2>&, const ::TemplateIntToType<1>&, const ::TemplateIntToType<0>&, const string& methodName, const METHOD& method) { std::function actualMethod = method; InvokeFunction implementation = [actualMethod](const Context&, const string& method, const string&, string& result) -> uint32_t { @@ -1124,7 +1116,7 @@ namespace Core { Register(methodName, implementation); } template - void InternalRegisterWithIndex(const ::TemplateIntToType<0>&, const ::TemplateIntToType<0>&, const ::TemplateIntToType<0>&, const string& methodName, const METHOD& method) + void InternalRegister(const ::TemplateIntToType<2>&, const ::TemplateIntToType<0>&, const ::TemplateIntToType<0>&, const string& methodName, const METHOD& method) { std::function actualMethod = method; InvokeFunction implementation = [actualMethod](const Context&, const string& method, const string& parameters, string& result) -> uint32_t { @@ -1302,34 +1294,44 @@ namespace Core { }; Register(methodName, implementation); } - template - void InternalRegisterWithIndex(const ::TemplateIntToType<1>&, const ::TemplateIntToType<0>&, const ::TemplateIntToType<1>&, const string& methodName, const METHOD& method) + template + void InternalRegister(const ::TemplateIntToType<1>&, const ::TemplateIntToType<1>&, const ::TemplateIntToType<1>&, const string& methodName, const METHOD& method, REALOBJECT* objectPtr) { - std::function actualMethod = method; - InvokeFunction implementation = [actualMethod](const Core::JSONRPC::Context& context, const string& method, const string& parameters, string& result) -> uint32_t { + std::function actualMethod = std::bind(method, objectPtr, std::placeholders::_1); + InvokeFunction implementation = [actualMethod](const Context& context, const string&, const string&, string&) -> uint32_t { + return (actualMethod(context)); + }; + Register(methodName, implementation); + } + template + void InternalRegister(const ::TemplateIntToType<1>&, const ::TemplateIntToType<0>&, const ::TemplateIntToType<1>&, const string& methodName, const METHOD& method, REALOBJECT* objectPtr) + { + std::function actualMethod = std::bind(method, objectPtr, std::placeholders::_1, std::placeholders::_2); + InvokeFunction implementation = [actualMethod](const Context& context, const string&, const string& parameters, string& result) -> uint32_t { uint32_t code; INBOUND inbound; Core::OptionalType report; - inbound.FromString(parameters, report); + inbound.FromString(parameters); if (report.IsSet() == false) { - code = actualMethod(context, Message::Index(method), inbound); + code = actualMethod(context, inbound); } else { code = Core::ERROR_PARSE_FAILURE; result = report.Value().Message(); } + return (code); }; Register(methodName, implementation); } - template - void InternalRegisterWithIndex(const ::TemplateIntToType<1>&, const ::TemplateIntToType<1>&, const ::TemplateIntToType<0>&, const string& methodName, const METHOD& method) + template + void InternalRegister(const ::TemplateIntToType<1>&, const ::TemplateIntToType<1>&, const ::TemplateIntToType<0>&, const string& methodName, const METHOD& method, REALOBJECT* objectPtr) { - std::function actualMethod = method; - InvokeFunction implementation = [actualMethod](const Core::JSONRPC::Context& context, const string& method, const string&, string& result) -> uint32_t { + std::function actualMethod = std::bind(method, objectPtr, std::placeholders::_1, std::placeholders::_2); + InvokeFunction implementation = [actualMethod](const Context& context, const string&, const string&, string& result) -> uint32_t { OUTBOUND outbound; - uint32_t code = actualMethod(context, Message::Index(method), outbound); + uint32_t code = actualMethod(context, outbound); if (code == Core::ERROR_NONE) { outbound.ToString(result); } @@ -1340,19 +1342,19 @@ namespace Core { }; Register(methodName, implementation); } - template - void InternalRegisterWithIndex(const ::TemplateIntToType<1>&, const ::TemplateIntToType<0>&, const ::TemplateIntToType<0>&, const string& methodName, const METHOD& method) + template + void InternalRegister(const ::TemplateIntToType<1>&, const ::TemplateIntToType<0>&, const ::TemplateIntToType<0>&, const string& methodName, const METHOD& method, REALOBJECT* objectPtr) { - std::function actualMethod = method; - InvokeFunction implementation = [actualMethod](const Core::JSONRPC::Context& context, const string& method, const string& parameters, string& result) -> uint32_t { + std::function actualMethod = std::bind(method, objectPtr, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); + InvokeFunction implementation = [actualMethod](const Context& context, const string&, const string& parameters, string& result) -> uint32_t { uint32_t code; INBOUND inbound; OUTBOUND outbound; Core::OptionalType report; - inbound.FromString(parameters, report); + inbound.FromString(parameters); if (report.IsSet() == false) { - code = actualMethod(context, Message::Index(method), inbound, outbound); + code = actualMethod(context, inbound, outbound); if (code == Core::ERROR_NONE) { outbound.ToString(result); } @@ -1370,43 +1372,32 @@ namespace Core { Register(methodName, implementation); } template - void InternalRegister(const ::TemplateIntToType<1>&, const ::TemplateIntToType<1>&, const ::TemplateIntToType<1>&, const string& methodName, const METHOD& method, REALOBJECT* objectPtr) - { - std::function actualMethod = std::bind(method, objectPtr); - InvokeFunction implementation = [actualMethod](const Context& context, const string&, const string&, string&) -> uint32_t { - return (actualMethod(context)); - }; - Register(methodName, implementation); - } - template - void InternalRegister(const ::TemplateIntToType<1>&, const ::TemplateIntToType<0>&, const ::TemplateIntToType<1>&, const string& methodName, const METHOD& method, REALOBJECT* objectPtr) + void InternalRegister(const ::TemplateIntToType<2>&, const ::TemplateIntToType<0>&, const ::TemplateIntToType<1>&, const string& methodName, const METHOD& method, REALOBJECT* objectPtr) { - std::function actualMethod = std::bind(method, objectPtr, std::placeholders::_1); - InvokeFunction implementation = [actualMethod](const Context& context, const string&, const string& parameters, string& result) -> uint32_t { + std::function actualMethod = std::bind(method, objectPtr, std::placeholders::_1, std::placeholders::_2); + InvokeFunction implementation = [actualMethod](const Context&, const string& methodName, const string& parameters, string& result) -> uint32_t { uint32_t code; INBOUND inbound; Core::OptionalType report; - inbound.FromString(parameters); - + inbound.FromString(parameters, report); if (report.IsSet() == false) { - code = actualMethod(context, inbound); + code = actualMethod(Message::Index(methodName), inbound); } else { code = Core::ERROR_PARSE_FAILURE; result = report.Value().Message(); } - return (code); }; Register(methodName, implementation); } template - void InternalRegister(const ::TemplateIntToType<1>&, const ::TemplateIntToType<1>&, const ::TemplateIntToType<0>&, const string& methodName, const METHOD& method, REALOBJECT* objectPtr) + void InternalRegister(const ::TemplateIntToType<2>&, const ::TemplateIntToType<1>&, const ::TemplateIntToType<0>&, const string& methodName, const METHOD& method, REALOBJECT* objectPtr) { - std::function actualMethod = std::bind(method, objectPtr, std::placeholders::_1); - InvokeFunction implementation = [actualMethod](const Context& context, const string&, const string&, string& result) -> uint32_t { + std::function actualMethod = std::bind(method, objectPtr, std::placeholders::_1, std::placeholders::_2); + InvokeFunction implementation = [actualMethod](const Context&, const string& methodName, const string&, string& result) -> uint32_t { OUTBOUND outbound; - uint32_t code = actualMethod(context, outbound); + uint32_t code = actualMethod(Message::Index(methodName), outbound); if (code == Core::ERROR_NONE) { outbound.ToString(result); } @@ -1418,18 +1409,18 @@ namespace Core { Register(methodName, implementation); } template - void InternalRegister(const ::TemplateIntToType<1>&, const ::TemplateIntToType<0>&, const ::TemplateIntToType<0>&, const string& methodName, const METHOD& method, REALOBJECT* objectPtr) + void InternalRegister(const ::TemplateIntToType<2>&, const ::TemplateIntToType<0>&, const ::TemplateIntToType<0>&, const string& methodName, const METHOD& method, REALOBJECT* objectPtr) { - std::function actualMethod = std::bind(method, objectPtr, std::placeholders::_1, std::placeholders::_2); - InvokeFunction implementation = [actualMethod](const Context& context, const string&, const string& parameters, string& result) -> uint32_t { + std::function actualMethod = std::bind(method, objectPtr, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); + InvokeFunction implementation = [actualMethod](const Context&, const string& methodName, const string& parameters, string& result) -> uint32_t { uint32_t code; INBOUND inbound; OUTBOUND outbound; Core::OptionalType report; - inbound.FromString(parameters); + inbound.FromString(parameters, report); if (report.IsSet() == false) { - code = actualMethod(context, inbound, outbound); + code = actualMethod(Message::Index(methodName), inbound, outbound); if (code == Core::ERROR_NONE) { outbound.ToString(result); } diff --git a/Source/plugins/IShell.h b/Source/plugins/IShell.h index 8f5c73687..722b30faa 100644 --- a/Source/plugins/IShell.h +++ b/Source/plugins/IShell.h @@ -40,15 +40,17 @@ namespace PluginHost { // be used to instantiate new objects (COM objects) in a new process, or monitor the state of such a process. // If this interface is requested outside of the main process, it will return a nullptr. /* @stubgen:omit */ - struct EXTERNAL ICOMLink { + struct EXTERNAL ICOMLink : virtual public Core::IUnknown { + + enum { ID = RPC::ID_SHELL_COMLINK }; struct INotification : virtual public Core::IUnknown { - virtual ~INotification() = default; virtual void Dangling(const Core::IUnknown* source, const uint32_t interfaceId) = 0; virtual void Revoked(const Core::IUnknown* remote, const uint32_t interfaceId) = 0; }; virtual ~ICOMLink() = default; + virtual void Register(RPC::IRemoteConnection::INotification* sink) = 0; virtual void Unregister(const RPC::IRemoteConnection::INotification* sink) = 0; @@ -59,6 +61,22 @@ namespace PluginHost { virtual void* Instantiate(const RPC::Object& object, const uint32_t waitTime, uint32_t& connectionId) = 0; }; + struct EXTERNAL IConnectionServer : virtual public Core::IUnknown { + + enum { ID = RPC::ID_SHELL_CONNECTIONSERVER }; + + struct INotification : virtual public Core::IUnknown { + + enum { ID = RPC::ID_SHELL_CONNECTIONSERVER_NOTIFICATION }; + + virtual void Opened(const uint32_t channelId) = 0; + virtual void Closed(const uint32_t channelId) = 0; + }; + + virtual void Register(INotification* sink) = 0; + virtual void Unregister(const INotification* sink) = 0; + }; + enum class startmode : uint8_t { UNAVAILABLE, DEACTIVATED, @@ -255,66 +273,82 @@ namespace PluginHost { virtual Core::hresult Hibernate(const uint32_t timeout) = 0; virtual reason Reason() const = 0; + virtual void Register(IConnectionServer::INotification* sink) = 0; + virtual void Unregister(const IConnectionServer::INotification* sink) = 0; + // Method to access, in the main process space, the channel factory to submit JSON objects to be send. // This method will return a error if it is NOT in the main process. /* @stubgen:stub */ virtual uint32_t Submit(const uint32_t Id, const Core::ProxyType& response) = 0; - // Method to access, in the main space, a COM factory to instantiate objects out-of-process. - // This method will return a nullptr if it is NOT in the main process. - /* @stubgen:stub */ - virtual ICOMLink* COMLink() = 0; - inline void Register(RPC::IRemoteConnection::INotification* sink) { - ICOMLink* handler(COMLink()); + ASSERT(sink != nullptr); + + ICOMLink* handler(QueryInterface()); // This method can only be used in the main process. Only this process, can instantiate a new process ASSERT(handler != nullptr); if (handler != nullptr) { handler->Register(sink); + handler->Release(); } } inline void Unregister(const RPC::IRemoteConnection::INotification* sink) { - ICOMLink* handler(COMLink()); + ASSERT(sink != nullptr); + + ICOMLink* handler(QueryInterface()); // This method can only be used in the main process. Only this process, can instantiate a new process ASSERT(handler != nullptr); if (handler != nullptr) { handler->Unregister(sink); + handler->Release(); } } inline void Register(ICOMLink::INotification* sink) { - ICOMLink* handler(COMLink()); + ASSERT(sink != nullptr); + + ICOMLink* handler(QueryInterface()); ASSERT(handler != nullptr); if (handler != nullptr) { handler->Register(sink); + handler->Release(); } } inline void Unregister(ICOMLink::INotification* sink) { - ICOMLink* handler(COMLink()); + ASSERT(sink != nullptr); + + ICOMLink* handler(QueryInterface()); ASSERT(handler != nullptr); if (handler != nullptr) { handler->Unregister(sink); + handler->Release(); } } inline RPC::IRemoteConnection* RemoteConnection(const uint32_t connectionId) { - ICOMLink* handler(COMLink()); + RPC::IRemoteConnection* connection(nullptr); + ICOMLink* handler(QueryInterface()); // This method can only be used in the main process. Only this process, can instantiate a new process ASSERT(handler != nullptr); - return (handler == nullptr ? nullptr : handler->RemoteConnection(connectionId)); + if (handler != nullptr) { + connection = handler->RemoteConnection(connectionId); + handler->Release(); + } + + return (connection); } inline uint32_t EnablePersistentStorage(uint16_t permission = 0, const string& user = {}, const string& group = {}) { diff --git a/Source/plugins/JSONRPC.cpp b/Source/plugins/JSONRPC.cpp index e1e818892..a079eb002 100644 --- a/Source/plugins/JSONRPC.cpp +++ b/Source/plugins/JSONRPC.cpp @@ -32,6 +32,7 @@ namespace WPEFramework { , _versions() , _observers() , _eventAliases() + , _notification(*this) { std::vector versions = { 1 }; @@ -47,6 +48,7 @@ namespace WPEFramework { , _versions() , _observers() , _eventAliases() + , _notification(*this) { _handlers.emplace_back(versions); } @@ -60,6 +62,7 @@ namespace WPEFramework { , _versions() , _observers() , _eventAliases() + , _notification(*this) { std::vector versions = { 1 }; @@ -75,6 +78,7 @@ namespace WPEFramework { , _versions() , _observers() , _eventAliases() + , _notification(*this) { _handlers.emplace_back(versions); } diff --git a/Source/plugins/JSONRPC.h b/Source/plugins/JSONRPC.h index 9e3075f46..d9b4937c1 100644 --- a/Source/plugins/JSONRPC.h +++ b/Source/plugins/JSONRPC.h @@ -34,11 +34,42 @@ namespace PluginHost { virtual void Activate(IShell* service) = 0; virtual void Deactivate() = 0; - virtual void Dropped(const uint32_t channelId) = 0; virtual void Dropped(const IDispatcher::ICallback* callback) = 0; }; class EXTERNAL JSONRPC : public ILocalDispatcher { + private: + class Notification : public IShell::IConnectionServer::INotification { + public: + Notification(JSONRPC& parent) + : _parent(parent) + { + } + ~Notification() = default; + + Notification(const Notification&) = delete; + Notification(Notification&&) = delete; + Notification& operator=(const Notification&) = delete; + Notification& operator=(Notification&&) = delete; + + public: + void Opened(const uint32_t channelId VARIABLE_IS_NOT_USED) override + { + } + void Closed(const uint32_t channelId) override + { + _parent.ChannelClosed(channelId); + } + + public: + BEGIN_INTERFACE_MAP(Notification) + INTERFACE_ENTRY(IShell::IConnectionServer::INotification) + END_INTERFACE_MAP + + private: + JSONRPC& _parent; + }; + private: class Observer { private: @@ -547,6 +578,9 @@ namespace PluginHost { parameters.ToString(subject); return InternalNotify(event, subject, std::move(method)); } + Core::hresult Event(const string& eventId, const string& parameters) { + return (InternalNotify(eventId, parameters)); + } void Response(const uint32_t channelId, const Core::ProxyType& message) { _service->Submit(channelId, message); } @@ -691,38 +725,20 @@ namespace PluginHost { { _adminLock.Lock(); - _observers.clear(); - if (_service != nullptr) { + if (_observers.empty() == false) { + _service->Unregister(&_notification); + } + _service->Release(); _service = nullptr; } - _adminLock.Unlock(); - } - void Dropped(const uint32_t channelId) override - { - _adminLock.Lock(); - - ObserverMap::iterator index = _observers.begin(); - - while (index != _observers.end()) { - - index->second.Dropped(channelId); - - if (index->second.IsEmpty() == true) { - index = _observers.erase(index); - } - else { - index++; - } - } + _callsign.clear(); + _observers.clear(); _adminLock.Unlock(); } - Core::hresult Event(const string& eventId, const string& parameters) { - return (InternalNotify(eventId, parameters)); - } // Inherited via IDispatcher::ICallback // --------------------------------------------------------------------------------- @@ -791,6 +807,12 @@ namespace PluginHost { ObserverMap::iterator index = _observers.find(eventId); if (index == _observers.end()) { + + if (_observers.empty() == true) { + ASSERT(_service != nullptr); + _service->Register(&_notification); + } + index = _observers.emplace(std::piecewise_construct, std::forward_as_tuple(eventId), std::forward_as_tuple()).first; @@ -815,6 +837,9 @@ namespace PluginHost { if ((result == Core::ERROR_NONE) && (index->second.IsEmpty() == true)) { _observers.erase(index); + + ASSERT(_service != nullptr); + _service->Unregister(&_notification); } } @@ -823,6 +848,34 @@ namespace PluginHost { return (result); } + private: + void ChannelClosed(const uint32_t channelId) + { + _adminLock.Lock(); + + ObserverMap::iterator index = _observers.begin(); + + while (index != _observers.end()) { + + index->second.Dropped(channelId); + + if (index->second.IsEmpty() == true) { + index = _observers.erase(index); + + if (_observers.empty() == true) { + ASSERT(_service != nullptr); + + _service->Unregister(&_notification); + } + } + else { + index++; + } + } + + _adminLock.Unlock(); + } + private: uint32_t InternalNotify(const string& event, const string& parameters, const std::function& sendifmethod = std::function()) const { @@ -884,6 +937,7 @@ namespace PluginHost { VersionList _versions; ObserverMap _observers; EventAliasesMap _eventAliases; + Core::SinkType _notification; }; class EXTERNAL JSONRPCSupportsEventStatus : public PluginHost::JSONRPC { diff --git a/Source/plugins/Shell.cpp b/Source/plugins/Shell.cpp index f6e5015e8..7f0220e03 100644 --- a/Source/plugins/Shell.cpp +++ b/Source/plugins/Shell.cpp @@ -59,7 +59,7 @@ namespace PluginHost } } } else { - ICOMLink* handler(COMLink()); + ICOMLink* handler(QueryInterface()); // This method can only be used in the main process. Only this process, can instantiate a new process ASSERT(handler != nullptr);