From: Jaemin Ryu Date: Mon, 16 Oct 2017 05:55:25 +0000 (+0900) Subject: Add common exception handling X-Git-Tag: submit/tizen_4.0/20171129.062733~4 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F64%2F155764%2F7;p=platform%2Fcore%2Fsecurity%2Fklay.git Add common exception handling Change-Id: I4a444fc90086fedc82fdf3afb34eba1d440ccdd0 Signed-off-by: Jaemin Ryu --- diff --git a/include/klay/exception.h b/include/klay/exception.h index 734019a..81eee69 100644 --- a/include/klay/exception.h +++ b/include/klay/exception.h @@ -28,6 +28,46 @@ public: std::runtime_error(error) { } + + virtual ~Exception() {} + virtual const char *name() const; + virtual const char *className() const; }; + +#define EXCEPTION_DEFINE(CLS) \ + class CLS : public Exception { \ + public: \ + CLS(const std::string& error); \ + ~CLS() {} \ + const char *className() const; \ + const char *name() const; \ + }; + + +#define EXCEPTION_IMPLEMENT(CLS, NAME) \ + CLS::CLS(const std::string& error) : \ + Exception(error) \ + { \ + } \ + const char *CLS::className() const \ + { \ + return STRINGIFY(CLS); \ + } \ + const char *CLS::name() const \ + { \ + return NAME; \ + } + +EXCEPTION_DEFINE(AssertionViolationException) +EXCEPTION_DEFINE(NullPointerException) +EXCEPTION_DEFINE(InvalidArgumentException) +EXCEPTION_DEFINE(NotImplementedException) +EXCEPTION_DEFINE(RangeException) +EXCEPTION_DEFINE(NotFoundException) +EXCEPTION_DEFINE(UnsupportedException) +EXCEPTION_DEFINE(TimeoutException) +EXCEPTION_DEFINE(NoPermissionException) +EXCEPTION_DEFINE(OutOfMemoryException) +EXCEPTION_DEFINE(IOException) } // namespace runtime #endif //__RUNTIME_EXCEPTION_H__ diff --git a/include/klay/rmi/client.h b/include/klay/rmi/client.h index dfb43a6..d0c81e6 100644 --- a/include/klay/rmi/client.h +++ b/include/klay/rmi/client.h @@ -29,13 +29,14 @@ namespace rmi { -class Client { +template +class RemoteAccessClient { public: - Client(const std::string& address); - virtual ~Client(); + RemoteAccessClient(const std::string& address); + virtual ~RemoteAccessClient(); - Client(const Client&) = delete; - Client& operator=(const Client&) = delete; + RemoteAccessClient(const RemoteAccessClient&) = delete; + RemoteAccessClient& operator=(const RemoteAccessClient&) = delete; void connect(); void disconnect(); @@ -58,8 +59,70 @@ private: std::thread dispatcher; }; -template -int Client::subscribe(const std::string& provider, const std::string& name, +template +RemoteAccessClient::RemoteAccessClient(const std::string& path) : + address(path) +{ +} + +template +RemoteAccessClient::~RemoteAccessClient() +{ + try { + disconnect(); + } catch (runtime::Exception& e) {} +} + +template +void RemoteAccessClient::connect() +{ + connection = std::make_shared(Socket::connect(address)); + + dispatcher = std::thread([this] { mainloop.run(); }); +} + +template +int RemoteAccessClient::unsubscribe(const std::string& provider, int id) +{ + // file descriptor(id) is automatically closed when mainloop callback is destroyed. + mainloop.removeEventSource(id); + return 0; +} + +template +int RemoteAccessClient::subscribe(const std::string& provider, const std::string& name) +{ + Message request = connection->createMessage(Message::MethodCall, provider); + request.packParameters(name); + connection->send(request); + + runtime::FileDescriptor response; + Message reply = connection->dispatch(); + if (reply.isError()) { + std::string klass; + reply.disclose(klass); + + ExceptionModel exception; + exception.raise(reply.target(), klass); + } + + reply.disclose(response); + + return response.fileDescriptor; +} + +template +void RemoteAccessClient::disconnect() +{ + mainloop.stop(); + if (dispatcher.joinable()) { + dispatcher.join(); + } +} + +template +template +int RemoteAccessClient::subscribe(const std::string& provider, const std::string& name, const typename MethodHandler::type& handler) { int id = subscribe(provider, name); @@ -91,8 +154,9 @@ int Client::subscribe(const std::string& provider, const std::string& name, return id; } -template -Type Client::methodCall(const std::string& method, Args&&... args) +template +template +Type RemoteAccessClient::methodCall(const std::string& method, Args&&... args) { Message request = connection->createMessage(Message::MethodCall, method); request.packParameters(std::forward(args)...); @@ -100,10 +164,24 @@ Type Client::methodCall(const std::string& method, Args&&... args) Type response; Message reply = connection->dispatch(); + if (reply.isError()) { + std::string klass; + reply.disclose(klass); + ExceptionModel exception; + exception.raise(reply.target(), klass); + } + reply.disclose(response); return response; } +class DefaultExceptionModel { +public: + void raise(const std::string& target, const std::string& except); +}; + +using Client = RemoteAccessClient; + } // namespace rmi #endif //__RMI_CLIENT_H__ diff --git a/include/klay/rmi/message.h b/include/klay/rmi/message.h index 3d36671..7ac0208 100644 --- a/include/klay/rmi/message.h +++ b/include/klay/rmi/message.h @@ -51,7 +51,7 @@ public: // [TBD] Take arguments Message createReplyMessage() const; - Message createErrorMessage(const std::string& message) const; + Message createErrorMessage(const std::string& target, const std::string& message) const; unsigned int id() const { diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 832c6ba..2b3c4d9 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -17,6 +17,7 @@ SET(LIB_VERSION "${VERSION}") SET(LIB_SOVERSION "0") SET (KLAY_SOURCES ${KLAY_SRC}/error.cpp + ${KLAY_SRC}/exception.cpp ${KLAY_SRC}/cgroup.cpp ${KLAY_SRC}/process.cpp ${KLAY_SRC}/eventfd.cpp diff --git a/src/exception.cpp b/src/exception.cpp new file mode 100644 index 0000000..e7cd928 --- /dev/null +++ b/src/exception.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +#include +#include + +namespace runtime { + +const char *Exception::name() const +{ + return "Exception"; +} + +const char *Exception::className() const +{ + return name(); +} + +EXCEPTION_IMPLEMENT(AssertionViolationException, "Assertion violation") +EXCEPTION_IMPLEMENT(NullPointerException, "Null pointer") +EXCEPTION_IMPLEMENT(InvalidArgumentException, "Invalid argument") +EXCEPTION_IMPLEMENT(NotImplementedException, "Not implemented") +EXCEPTION_IMPLEMENT(RangeException, "Out og range") +EXCEPTION_IMPLEMENT(NotFoundException, "Not found") +EXCEPTION_IMPLEMENT(UnsupportedException, "Unsupported") +EXCEPTION_IMPLEMENT(TimeoutException, "Timeout") +EXCEPTION_IMPLEMENT(NoPermissionException, "No permission") +EXCEPTION_IMPLEMENT(OutOfMemoryException, "Out of memory") +EXCEPTION_IMPLEMENT(IOException, "I/O error") +} // namespace runtime diff --git a/src/rmi/client.cpp b/src/rmi/client.cpp index d6e7bfa..c4e7f03 100644 --- a/src/rmi/client.cpp +++ b/src/rmi/client.cpp @@ -13,55 +13,31 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include #include namespace rmi { -Client::Client(const std::string& path) : - address(path) +void DefaultExceptionModel::raise(const std::string& target, const std::string& msg) { -} - -Client::~Client() -{ - try { - disconnect(); - } catch (runtime::Exception& e) {} -} - -void Client::connect() -{ - connection = std::make_shared(Socket::connect(address)); - - dispatcher = std::thread([this] { mainloop.run(); }); -} - -int Client::unsubscribe(const std::string& provider, int id) -{ - // file descriptor(id) is automatically closed when mainloop callback is destroyed. - mainloop.removeEventSource(id); - return 0; -} - -int Client::subscribe(const std::string& provider, const std::string& name) -{ - Message request = connection->createMessage(Message::MethodCall, provider); - request.packParameters(name); - connection->send(request); - - runtime::FileDescriptor response; - Message reply = connection->dispatch(); - reply.disclose(response); - - return response.fileDescriptor; -} - -void Client::disconnect() -{ - mainloop.stop(); - if (dispatcher.joinable()) { - dispatcher.join(); - } + if (target == "InvalidArgumentException") + throw runtime::InvalidArgumentException(msg); + else if (target == "NotImplementedException") + throw runtime::InvalidArgumentException(msg); + else if (target == "RangeException") + throw runtime::RangeException(msg); + else if (target == "NotFoundException") + throw runtime::NotFoundException(msg); + else if (target == "UnsupportedException") + throw runtime::UnsupportedException(msg); + else if (target == "NoPermissionException") + throw runtime::NoPermissionException(msg); + else if (target == "IOException") + throw runtime::IOException(msg); + else if (target == "OutOfMemoryException") + throw runtime::OutOfMemoryException(msg); + else + throw runtime::Exception(msg); } } // namespace rmi diff --git a/src/rmi/connection.cpp b/src/rmi/connection.cpp index 4190115..1ecd54a 100644 --- a/src/rmi/connection.cpp +++ b/src/rmi/connection.cpp @@ -46,12 +46,6 @@ Message Connection::dispatch() const std::lock_guard lock(receiveMutex); message.decode(socket); - if (message.isError()) { - std::string exception; - message.disclose(exception); - - throw runtime::Exception(exception); - } return message; } diff --git a/src/rmi/message.cpp b/src/rmi/message.cpp index cd1a019..9dcaa28 100644 --- a/src/rmi/message.cpp +++ b/src/rmi/message.cpp @@ -81,9 +81,9 @@ Message Message::createReplyMessage() const return Message(id(), Reply, target()); } -Message Message::createErrorMessage(const std::string& message) const +Message Message::createErrorMessage(const std::string& target, const std::string& message) const { - Message error(id(), Error, target()); + Message error(id(), Error, target); error.enclose(message); return error; diff --git a/src/rmi/service.cpp b/src/rmi/service.cpp index c6b9188..66bcc61 100644 --- a/src/rmi/service.cpp +++ b/src/rmi/service.cpp @@ -197,20 +197,25 @@ void Service::onMessageProcess(const std::shared_ptr& connection) // we should increase the reference count of the shared_ptr by capturing it as value auto process = [&, connection](Message& request) { try { + if (!methodRegistry.count(request.target())) + throw runtime::NotFoundException("Method not found"); + std::shared_ptr methodContext = methodRegistry.at(request.target()); processingContext = ProcessingContext(connection); bool allowed = onPrivilegeCheck(processingContext.credentials, methodContext->privilege); onAuditTrail(processingContext.credentials, request.target(), allowed); if (!allowed) { - throw runtime::Exception("Permission denied"); + throw runtime::NoPermissionException("Permission denied"); } connection->send(methodContext->dispatcher(request)); + } catch (runtime::Exception& e) { + connection->send(request.createErrorMessage(e.className(), e.what())); } catch (std::exception& e) { try { // Forward the exception to the peer - connection->send(request.createErrorMessage(e.what())); + connection->send(request.createErrorMessage("Exception", e.what())); } catch (std::exception& ex) { // The connection is abnormally closed by the peer. ERROR(KSINK, ex.what());