From: Jan Olszak Date: Tue, 20 Jan 2015 15:15:39 +0000 (+0100) Subject: IPC: Support older glib X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=ca9d04423d356228266a2480231e77b624cf5876;p=platform%2Fcore%2Fsecurity%2Fvasum.git IPC: Support older glib [Bug/Feature] Replaced new calls with older equivalents Fixed SIGSEGV bug [Cause] N/A [Solution] N/A [Verification] Build, install, run tests, run tests under valgrind Change-Id: I572321fb4055f8f5b033b755c883c3e4b00bfcda --- diff --git a/common/ipc/client.cpp b/common/ipc/client.cpp index 16f77e6..1b7ae56 100644 --- a/common/ipc/client.cpp +++ b/common/ipc/client.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved +* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Jan Olszak * @@ -36,6 +36,8 @@ Client::Client(const std::string& socketPath) mSocketPath(socketPath) { LOGS("Client Constructor"); + setNewPeerCallback(nullptr); + setRemovedPeerCallback(nullptr); } Client::~Client() @@ -52,10 +54,14 @@ void Client::start(const bool usesExternalPolling) { LOGS("Client start"); // Initialize the connection with the server + if (usesExternalPolling) { + startPoll(); + } + mProcessor.start(usesExternalPolling); + LOGD("Connecting to " + mSocketPath); auto socketPtr = std::make_shared(Socket::connectSocket(mSocketPath)); mServiceFD = mProcessor.addPeer(socketPtr); - mProcessor.start(usesExternalPolling); } bool Client::isStarted() @@ -65,21 +71,41 @@ bool Client::isStarted() void Client::stop() { - LOGS("Client Destructor"); + LOGS("Client stop"); mProcessor.stop(); + + if (mIPCGSourcePtr) { + stopPoll(); + } } -std::vector Client::getFDs() +void Client::startPoll() { - std::vector fds; - fds.push_back(mProcessor.getEventFD()); - fds.push_back(mServiceFD); + LOGS("Client startPoll"); + using namespace std::placeholders; + mIPCGSourcePtr = IPCGSource::create(std::bind(&Client::handle, this, _1, _2)); + mIPCGSourcePtr->addFD(mProcessor.getEventFD()); + mIPCGSourcePtr->attach(); +} + +void Client::stopPoll() +{ + LOGS("Client stopPoll"); - return fds; + mIPCGSourcePtr->removeFD(mProcessor.getEventFD()); + mIPCGSourcePtr->detach(); + mIPCGSourcePtr.reset(); } void Client::handle(const FileDescriptor fd, const short pollEvent) { + LOGS("Client handle"); + + if (!isStarted()) { + LOGW("Client stopped"); + return; + } + if (fd == mProcessor.getEventFD() && (pollEvent & POLLIN)) { mProcessor.handleEvent(); return; @@ -97,13 +123,29 @@ void Client::handle(const FileDescriptor fd, const short pollEvent) void Client::setNewPeerCallback(const PeerCallback& newPeerCallback) { LOGS("Client setNewPeerCallback"); - mProcessor.setNewPeerCallback(newPeerCallback); + auto callback = [newPeerCallback, this](FileDescriptor fd) { + if (mIPCGSourcePtr) { + mIPCGSourcePtr->addFD(fd); + } + if (newPeerCallback) { + newPeerCallback(fd); + } + }; + mProcessor.setNewPeerCallback(callback); } void Client::setRemovedPeerCallback(const PeerCallback& removedPeerCallback) { LOGS("Client setRemovedPeerCallback"); - mProcessor.setRemovedPeerCallback(removedPeerCallback); + auto callback = [removedPeerCallback, this](FileDescriptor fd) { + if (mIPCGSourcePtr) { + mIPCGSourcePtr->removeFD(fd); + } + if (removedPeerCallback) { + removedPeerCallback(fd); + } + }; + mProcessor.setRemovedPeerCallback(callback); } void Client::removeMethod(const MethodID methodID) diff --git a/common/ipc/client.hpp b/common/ipc/client.hpp index 7b86198..eedf81b 100644 --- a/common/ipc/client.hpp +++ b/common/ipc/client.hpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved +* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Jan Olszak * @@ -26,6 +26,7 @@ #define COMMON_IPC_CLIENT_HPP #include "ipc/internals/processor.hpp" +#include "ipc/ipc-gsource.hpp" #include "ipc/types.hpp" #include "logger/logger.hpp" @@ -72,13 +73,6 @@ public: void stop(); /** - * Used with an external polling loop - * - * @return vector of internal file descriptors - */ - std::vector getFDs(); - - /** * Used with an external polling loop. * Handles one event from the file descriptor. * @@ -111,7 +105,7 @@ public: * @param method method handling implementation */ template - void addMethodHandler(const MethodID methodID, + void setMethodHandler(const MethodID methodID, const typename MethodHandler::type& method); /** @@ -124,7 +118,7 @@ public: * @tparam ReceivedDataType data type to serialize */ template - void addSignalHandler(const MethodID methodID, + void setSignalHandler(const MethodID methodID, const typename SignalHandler::type& signal); /** @@ -175,25 +169,30 @@ public: const std::shared_ptr& data); private: + + void startPoll(); + void stopPoll(); + FileDescriptor mServiceFD; Processor mProcessor; std::string mSocketPath; + IPCGSource::Pointer mIPCGSourcePtr; }; template -void Client::addMethodHandler(const MethodID methodID, +void Client::setMethodHandler(const MethodID methodID, const typename MethodHandler::type& method) { - LOGS("Client addMethodHandler, methodID: " << methodID); - mProcessor.addMethodHandler(methodID, method); + LOGS("Client setMethodHandler, methodID: " << methodID); + mProcessor.setMethodHandler(methodID, method); } template -void Client::addSignalHandler(const MethodID methodID, +void Client::setSignalHandler(const MethodID methodID, const typename SignalHandler::type& handler) { - LOGS("Client addSignalHandler, methodID: " << methodID); - mProcessor.addSignalHandler(methodID, handler); + LOGS("Client setSignalHandler, methodID: " << methodID); + mProcessor.setSignalHandler(methodID, handler); } template diff --git a/common/ipc/internals/add-peer-request.hpp b/common/ipc/internals/add-peer-request.hpp index 05c5524..3409ba5 100644 --- a/common/ipc/internals/add-peer-request.hpp +++ b/common/ipc/internals/add-peer-request.hpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved +* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Jan Olszak * diff --git a/common/ipc/internals/finish-request.hpp b/common/ipc/internals/finish-request.hpp index 3019475..3fd4a4f 100644 --- a/common/ipc/internals/finish-request.hpp +++ b/common/ipc/internals/finish-request.hpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved +* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Jan Olszak * diff --git a/common/ipc/internals/method-request.hpp b/common/ipc/internals/method-request.hpp index f9860f7..36d3d7a 100644 --- a/common/ipc/internals/method-request.hpp +++ b/common/ipc/internals/method-request.hpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved +* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Jan Olszak * diff --git a/common/ipc/internals/processor.cpp b/common/ipc/internals/processor.cpp index 05c97aa..bdc8a8d 100644 --- a/common/ipc/internals/processor.cpp +++ b/common/ipc/internals/processor.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved +* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Jan Olszak * @@ -66,7 +66,7 @@ Processor::Processor(const std::string& logName, utils::signalBlock(SIGPIPE); using namespace std::placeholders; - addMethodHandlerInternal(REGISTER_SIGNAL_METHOD_ID, + setMethodHandlerInternal(REGISTER_SIGNAL_METHOD_ID, std::bind(&Processor::onNewSignals, this, _1, _2)); } @@ -94,6 +94,7 @@ void Processor::start(bool usesExternalPolling) if (!isStarted()) { LOGI(mLogPrefix + "Processor start"); mIsRunning = true; + mUsesExternalPolling = usesExternalPolling; if (!usesExternalPolling) { mThread = std::thread(&Processor::run, this); } @@ -228,7 +229,6 @@ void Processor::removePeerInternal(const FileDescriptor peerFD, Status status) mRemovedPeerCallback(peerFD); } - resetPolling(); } @@ -236,8 +236,7 @@ void Processor::resetPolling() { LOGS(mLogPrefix + "Processor resetPolling"); - if (!isStarted()) { - LOGW(mLogPrefix + "Processor not started! Polling not reset!"); + if (mUsesExternalPolling) { return; } @@ -681,7 +680,7 @@ bool Processor::onFinishRequest(FinishRequest& request) break; } case Event::REMOVE_PEER: { - request.get()->conditionPtr->notify_all(); + onRemovePeerRequest(*request.get()); break; } case Event::SIGNAL: @@ -692,6 +691,7 @@ bool Processor::onFinishRequest(FinishRequest& request) } mIsRunning = false; + request.conditionPtr->notify_all(); return true; } diff --git a/common/ipc/internals/processor.hpp b/common/ipc/internals/processor.hpp index 157f39c..40dd4c0 100644 --- a/common/ipc/internals/processor.hpp +++ b/common/ipc/internals/processor.hpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved +* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Jan Olszak * @@ -190,7 +190,7 @@ public: * @tparam ReceivedDataType data type to receive */ template - void addMethodHandler(const MethodID methodID, + void setMethodHandler(const MethodID methodID, const typename MethodHandler::type& process); /** @@ -208,7 +208,7 @@ public: * @tparam ReceivedDataType data type to receive */ template - void addSignalHandler(const MethodID methodID, + void setSignalHandler(const MethodID methodID, const typename SignalHandler::type& process); /** @@ -360,6 +360,7 @@ private: RequestQueue mRequestQueue; bool mIsRunning; + bool mUsesExternalPolling; std::unordered_map> mMethodsCallbacks; std::unordered_map> mSignalsCallbacks; @@ -381,7 +382,7 @@ private: std::thread mThread; template - void addMethodHandlerInternal(const MethodID methodID, + void setMethodHandlerInternal(const MethodID methodID, const typename MethodHandler::type& process); template @@ -420,7 +421,7 @@ private: }; template -void Processor::addMethodHandlerInternal(const MethodID methodID, +void Processor::setMethodHandlerInternal(const MethodID methodID, const typename MethodHandler::type& method) { MethodHandlers methodCall; @@ -447,7 +448,7 @@ void Processor::addMethodHandlerInternal(const MethodID methodID, } template -void Processor::addMethodHandler(const MethodID methodID, +void Processor::setMethodHandler(const MethodID methodID, const typename MethodHandler::type& method) { if (methodID == RETURN_METHOD_ID || methodID == REGISTER_SIGNAL_METHOD_ID) { @@ -463,13 +464,13 @@ void Processor::addMethodHandler(const MethodID methodID, throw IPCException("MethodID used by a signal: " + std::to_string(methodID)); } - addMethodHandlerInternal(methodID, method); + setMethodHandlerInternal(methodID, method); } } template -void Processor::addSignalHandler(const MethodID methodID, +void Processor::setSignalHandler(const MethodID methodID, const typename SignalHandler::type& handler) { if (methodID == RETURN_METHOD_ID || methodID == REGISTER_SIGNAL_METHOD_ID) { diff --git a/common/ipc/internals/remove-peer-request.hpp b/common/ipc/internals/remove-peer-request.hpp index ec01ac4..4ec07cb 100644 --- a/common/ipc/internals/remove-peer-request.hpp +++ b/common/ipc/internals/remove-peer-request.hpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved +* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Jan Olszak * diff --git a/common/ipc/internals/request-queue.hpp b/common/ipc/internals/request-queue.hpp index 35b5120..82ba606 100644 --- a/common/ipc/internals/request-queue.hpp +++ b/common/ipc/internals/request-queue.hpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved +* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Jan Olszak * diff --git a/common/ipc/internals/signal-request.hpp b/common/ipc/internals/signal-request.hpp index 4cf62c2..ad80d91 100644 --- a/common/ipc/internals/signal-request.hpp +++ b/common/ipc/internals/signal-request.hpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved +* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Jan Olszak * diff --git a/common/ipc/ipc-gsource.cpp b/common/ipc/ipc-gsource.cpp index 5a4e137..1769414 100644 --- a/common/ipc/ipc-gsource.cpp +++ b/common/ipc/ipc-gsource.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved +* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Jan Olszak * @@ -26,10 +26,9 @@ #include "config.hpp" #include "ipc/ipc-gsource.hpp" - -#if GLIB_CHECK_VERSION(2,36,0) - +#include "utils/callback-wrapper.hpp" #include "logger/logger.hpp" + #include namespace vasum { @@ -37,33 +36,26 @@ namespace ipc { namespace { +gushort conditions = static_cast(G_IO_IN | + G_IO_ERR | + G_IO_HUP); -GIOCondition conditions = static_cast(G_IO_IN | - G_IO_ERR | - G_IO_HUP); } - -IPCGSource::IPCGSource(const std::vector fds, - const HandlerCallback& handlerCallback) +IPCGSource::IPCGSource(const HandlerCallback& handlerCallback) : mHandlerCallback(handlerCallback) { - LOGS("IPCGSource constructor"); - - for (const FileDescriptor fd : fds) { - addFD(fd); - } + LOGT("IPCGSource Constructor"); } IPCGSource::~IPCGSource() { - LOGS("~IPCGSource"); + LOGT("IPCGSource Destructor"); } -IPCGSource::Pointer IPCGSource::create(const std::vector& fds, - const HandlerCallback& handlerCallback) +IPCGSource::Pointer IPCGSource::create(const HandlerCallback& handlerCallback) { - LOGS("Creating IPCGSource"); + LOGT("Creating IPCGSource"); static GSourceFuncs funcs = { &IPCGSource::prepare, &IPCGSource::check, @@ -79,64 +71,96 @@ IPCGSource::Pointer IPCGSource::create(const std::vector& fds, // Fill additional data IPCGSource* source = reinterpret_cast(gSource); - new(source)IPCGSource(fds, handlerCallback); + new(source) IPCGSource(handlerCallback); auto deleter = [](IPCGSource * ptr) { LOGD("Deleter"); - - if (!g_source_is_destroyed(&(ptr->mGSource))) { - // This way finalize method will be run in glib loop's thread - g_source_destroy(&(ptr->mGSource)); - } + g_source_unref(&ptr->mGSource); }; - return std::shared_ptr(source, deleter); + Pointer ipcGSourcePtr(source, deleter); + + g_source_set_callback(gSource, + &IPCGSource::onHandlerCall, + utils::createCallbackWrapper(Pointer(ipcGSourcePtr), ipcGSourcePtr->mGuard.spawn()), + &utils::deleteCallbackWrapper); + + return ipcGSourcePtr; } void IPCGSource::addFD(const FileDescriptor fd) { + LOGI("Adding to glib FD: " << fd); + Lock lock(mStateMutex); - if (!&mGSource) { - // In case it's called as a callback but the IPCGSource is destroyed - return; - } - LOGS("Adding fd to glib"); - - gpointer tag = g_source_add_unix_fd(&mGSource, - fd, - conditions); - FDInfo fdInfo(tag, fd); - mFDInfos.push_back(std::move(fdInfo)); + mGPollFDs.push_back({fd, conditions, 0}); + g_source_add_poll(&mGSource, &mGPollFDs.back()); } void IPCGSource::removeFD(const FileDescriptor fd) { - if (!&mGSource) { - // In case it's called as a callback but the IPCGSource is destroyed - return; - } + Lock lock(mStateMutex); + + auto it = std::find_if(mGPollFDs.begin(), mGPollFDs.end(), [fd](GPollFD gPollFD) { + return gPollFD.fd = fd; + }); - LOGS("Removing fd from glib"); - auto it = std::find(mFDInfos.begin(), mFDInfos.end(), fd); - if (it == mFDInfos.end()) { + if (it == mGPollFDs.end()) { LOGE("No such fd"); return; } - g_source_remove_unix_fd(&mGSource, it->tag); - mFDInfos.erase(it); + g_source_remove_poll(&mGSource, &(*it)); + mGPollFDs.erase(it); + LOGI("Removed from glib FD: " << fd); } guint IPCGSource::attach(GMainContext* context) { - LOGS("Attaching to GMainContext"); + LOGT("Attaching to GMainContext"); guint ret = g_source_attach(&mGSource, context); - g_source_unref(&mGSource); return ret; } +void IPCGSource::detach() +{ + LOGT("Detaching"); + Lock lock(mStateMutex); + + for (GPollFD gPollFD : mGPollFDs) { + g_source_remove_poll(&mGSource, &gPollFD); + } + + mGPollFDs.clear(); + if (!g_source_is_destroyed(&mGSource)) { + LOGD("Destroying"); + // This way finalize method will be run in glib loop's thread + g_source_destroy(&mGSource); + } +} + +void IPCGSource::callHandler() +{ + Lock lock(mStateMutex); + + for (const GPollFD& gPollFD : mGPollFDs) { + if (gPollFD.revents & conditions) { + mHandlerCallback(gPollFD.fd, gPollFD.revents); + } + } +} + +gboolean IPCGSource::onHandlerCall(gpointer userData) +{ + const auto& source = utils::getCallbackFromPointer(userData); + if (source) { + source->callHandler(); + } + return TRUE; +} + gboolean IPCGSource::prepare(GSource* gSource, gint* timeout) { - if (!gSource) { + if (!gSource || g_source_is_destroyed(gSource)) { return FALSE; } @@ -149,7 +173,7 @@ gboolean IPCGSource::prepare(GSource* gSource, gint* timeout) gboolean IPCGSource::check(GSource* gSource) { - if (!gSource) { + if (!gSource || g_source_is_destroyed(gSource)) { return FALSE; } @@ -157,21 +181,16 @@ gboolean IPCGSource::check(GSource* gSource) } gboolean IPCGSource::dispatch(GSource* gSource, - GSourceFunc /*callback*/, - gpointer /*userData*/) + GSourceFunc callback, + gpointer userData) { if (!gSource || g_source_is_destroyed(gSource)) { // Remove the GSource from the GMainContext return FALSE; } - IPCGSource* source = reinterpret_cast(gSource); - - for (const FDInfo fdInfo : source->mFDInfos) { - GIOCondition cond = g_source_query_unix_fd(gSource, fdInfo.tag); - if (conditions & cond) { - source->mHandlerCallback(fdInfo.fd, cond); - } + if (callback) { + callback(userData); } return TRUE; @@ -179,8 +198,6 @@ gboolean IPCGSource::dispatch(GSource* gSource, void IPCGSource::finalize(GSource* gSource) { - LOGS("IPCGSource Finalize"); - if (gSource) { IPCGSource* source = reinterpret_cast(gSource); source->~IPCGSource(); @@ -189,5 +206,3 @@ void IPCGSource::finalize(GSource* gSource) } // namespace ipc } // namespace vasum - -#endif // GLIB_CHECK_VERSION diff --git a/common/ipc/ipc-gsource.hpp b/common/ipc/ipc-gsource.hpp index bb9a096..87057db 100644 --- a/common/ipc/ipc-gsource.hpp +++ b/common/ipc/ipc-gsource.hpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved +* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Jan Olszak * @@ -26,12 +26,12 @@ #define COMMON_IPC_IPC_GSOURCE_HPP #include -#if GLIB_CHECK_VERSION(2,36,0) - -#include "ipc/service.hpp" #include "ipc/types.hpp" +#include "utils/callback-guard.hpp" #include +#include +#include namespace vasum { @@ -82,18 +82,32 @@ public: guint attach(GMainContext* context = nullptr); /** + * After this method quits handlerCallback will not be called + */ + void detach(); + + /** * Creates the IPCGSource class in the memory allocated by glib. * Calls IPCGSource's constructor * - * @param fds initial set of file descriptors * @param handlerCallback event handling callback * * @return pointer to the IPCGSource */ - static Pointer create(const std::vector& fds, - const HandlerCallback& handlerCallback); + static Pointer create(const HandlerCallback& handlerCallback); + + /** + * Callback for the dispatch function + */ + static gboolean onHandlerCall(gpointer userData); + + /** + * Locks the internal state mutex and calls the handler callback for each fd + */ + void callHandler(); private: + typedef std::unique_lock Lock; /** * GSourceFuncs' callback @@ -117,38 +131,18 @@ private: */ static void finalize(GSource* source); - - // Called only from IPCGSource::create - IPCGSource(const std::vector fds, - const HandlerCallback& handlerCallback); - - struct FDInfo { - FDInfo(gpointer tag, FileDescriptor fd) - : tag(tag), fd(fd) {} - - bool operator==(const gpointer t) - { - return t == tag; - } - - bool operator==(const FileDescriptor f) - { - return f == fd; - } - - gpointer tag; - FileDescriptor fd; - }; + IPCGSource(const HandlerCallback& handlerCallback); GSource mGSource; HandlerCallback mHandlerCallback; - std::vector mFDInfos; + std::list mGPollFDs; + utils::CallbackGuard mGuard; + std::recursive_mutex mStateMutex; + }; } // namespace ipc } // namespace vasum -#endif // GLIB_CHECK_VERSION - #endif // COMMON_IPC_IPC_GSOURCE_HPP diff --git a/common/ipc/service.cpp b/common/ipc/service.cpp index b96bcd4..9bf721b 100644 --- a/common/ipc/service.cpp +++ b/common/ipc/service.cpp @@ -1,26 +1,26 @@ -// /* -// * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved -// * -// * Contact: Jan Olszak -// * -// * 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 -// */ - -// /** -// * @file -// * @author Jan Olszak (j.olszak@samsung.com) -// * @brief Implementation of the IPC handling class -// */ +/* +* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved +* +* Contact: Jan Olszak +* +* 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 +*/ + +/** + * @file + * @author Jan Olszak (j.olszak@samsung.com) + * @brief Implementation of the IPC handling class + */ #include "config.hpp" @@ -36,11 +36,13 @@ namespace ipc { Service::Service(const std::string& socketPath, const PeerCallback& addPeerCallback, const PeerCallback& removePeerCallback) - : mProcessor("[SERVICE] ", addPeerCallback, removePeerCallback), + : mProcessor("[SERVICE] "), mAcceptor(socketPath, std::bind(&Processor::addPeer, &mProcessor, _1)) { LOGS("Service Constructor"); + setNewPeerCallback(addPeerCallback); + setRemovedPeerCallback(removePeerCallback); } Service::~Service() @@ -56,6 +58,9 @@ Service::~Service() void Service::start(const bool usesExternalPolling) { LOGS("Service start"); + if (usesExternalPolling) { + startPoll(); + } mProcessor.start(usesExternalPolling); // There can be an incoming connection from mAcceptor before mProcessor is listening, @@ -75,20 +80,43 @@ void Service::stop() LOGS("Service stop"); mAcceptor.stop(); mProcessor.stop(); + + if (mIPCGSourcePtr) { + stopPoll(); + } +} + +void Service::startPoll() +{ + LOGS("Service startPoll"); + + mIPCGSourcePtr = IPCGSource::create(std::bind(&Service::handle, this, _1, _2)); + mIPCGSourcePtr->addFD(mAcceptor.getEventFD()); + mIPCGSourcePtr->addFD(mAcceptor.getConnectionFD()); + mIPCGSourcePtr->addFD(mProcessor.getEventFD()); + mIPCGSourcePtr->attach(); } -std::vector Service::getFDs() +void Service::stopPoll() { - std::vector fds; - fds.push_back(mAcceptor.getEventFD()); - fds.push_back(mAcceptor.getConnectionFD()); - fds.push_back(mProcessor.getEventFD()); + LOGS("Service stopPoll"); - return fds; + mIPCGSourcePtr->removeFD(mAcceptor.getEventFD()); + mIPCGSourcePtr->removeFD(mAcceptor.getConnectionFD()); + mIPCGSourcePtr->removeFD(mProcessor.getEventFD()); + mIPCGSourcePtr->detach(); + mIPCGSourcePtr.reset(); } void Service::handle(const FileDescriptor fd, const short pollEvent) { + LOGS("Service handle"); + + if (!isStarted()) { + LOGW("Service stopped"); + return; + } + if (fd == mProcessor.getEventFD() && (pollEvent & POLLIN)) { mProcessor.handleEvent(); return; @@ -111,17 +139,32 @@ void Service::handle(const FileDescriptor fd, const short pollEvent) } } - void Service::setNewPeerCallback(const PeerCallback& newPeerCallback) { LOGS("Service setNewPeerCallback"); - mProcessor.setNewPeerCallback(newPeerCallback); + auto callback = [newPeerCallback, this](FileDescriptor fd) { + if (mIPCGSourcePtr) { + mIPCGSourcePtr->addFD(fd); + } + if (newPeerCallback) { + newPeerCallback(fd); + } + }; + mProcessor.setNewPeerCallback(callback); } void Service::setRemovedPeerCallback(const PeerCallback& removedPeerCallback) { LOGS("Service setRemovedPeerCallback"); - mProcessor.setRemovedPeerCallback(removedPeerCallback); + auto callback = [removedPeerCallback, this](FileDescriptor fd) { + if (mIPCGSourcePtr) { + mIPCGSourcePtr->removeFD(fd); + } + if (removedPeerCallback) { + removedPeerCallback(fd); + } + }; + mProcessor.setRemovedPeerCallback(callback); } void Service::removeMethod(const MethodID methodID) diff --git a/common/ipc/service.hpp b/common/ipc/service.hpp index 9392a42..34b73fd 100644 --- a/common/ipc/service.hpp +++ b/common/ipc/service.hpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved +* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Jan Olszak * @@ -27,6 +27,7 @@ #include "ipc/internals/processor.hpp" #include "ipc/internals/acceptor.hpp" +#include "ipc/ipc-gsource.hpp" #include "ipc/types.hpp" #include "logger/logger.hpp" @@ -77,13 +78,6 @@ public: void stop(); /** - * Used with an external polling loop - * - * @return vector of internal file descriptors - */ - std::vector getFDs(); - - /** * Used with an external polling loop. * Handles one event from the file descriptor. * @@ -116,7 +110,7 @@ public: * @param method method handling implementation */ template - void addMethodHandler(const MethodID methodID, + void setMethodHandler(const MethodID methodID, const typename MethodHandler::type& method); /** @@ -129,7 +123,7 @@ public: * @tparam ReceivedDataType data type to serialize */ template - void addSignalHandler(const MethodID methodID, + void setSignalHandler(const MethodID methodID, const typename SignalHandler::type& handler); /** @@ -180,26 +174,31 @@ public: void signal(const MethodID methodID, const std::shared_ptr& data); private: + + void startPoll(); + void stopPoll(); + typedef std::lock_guard Lock; Processor mProcessor; Acceptor mAcceptor; + IPCGSource::Pointer mIPCGSourcePtr; }; template -void Service::addMethodHandler(const MethodID methodID, +void Service::setMethodHandler(const MethodID methodID, const typename MethodHandler::type& method) { - LOGS("Service addMethodHandler, methodID " << methodID); - mProcessor.addMethodHandler(methodID, method); + LOGS("Service setMethodHandler, methodID " << methodID); + mProcessor.setMethodHandler(methodID, method); } template -void Service::addSignalHandler(const MethodID methodID, +void Service::setSignalHandler(const MethodID methodID, const typename SignalHandler::type& handler) { - LOGS("Service addSignalHandler, methodID " << methodID); - mProcessor.addSignalHandler(methodID, handler); + LOGS("Service setSignalHandler, methodID " << methodID); + mProcessor.setSignalHandler(methodID, handler); } template diff --git a/common/ipc/types.cpp b/common/ipc/types.cpp index ba4c1c4..5d7dab6 100644 --- a/common/ipc/types.cpp +++ b/common/ipc/types.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved +* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Jan Olszak * diff --git a/common/ipc/types.hpp b/common/ipc/types.hpp index 10b87df..6186f65 100644 --- a/common/ipc/types.hpp +++ b/common/ipc/types.hpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved +* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved * * Contact: Jan Olszak * diff --git a/tests/unit_tests/ipc/ut-ipc.cpp b/tests/unit_tests/ipc/ut-ipc.cpp index c14b2a0..a15027c 100644 --- a/tests/unit_tests/ipc/ut-ipc.cpp +++ b/tests/unit_tests/ipc/ut-ipc.cpp @@ -33,7 +33,6 @@ #include "ipc/service.hpp" #include "ipc/client.hpp" -#include "ipc/ipc-gsource.hpp" #include "ipc/types.hpp" #include "utils/glib-loop.hpp" #include "utils/latch.hpp" @@ -148,7 +147,7 @@ std::shared_ptr longEchoCallback(const FileDescriptor, std::shared_ptr return data; } -FileDescriptor connect(Service& s, Client& c) +FileDescriptor connect(Service& s, Client& c, bool isServiceGlib = false, bool isClientGlib = false) { // Connects the Client to the Service and returns Clients FileDescriptor ValueLatch peerFDLatch; @@ -159,10 +158,10 @@ FileDescriptor connect(Service& s, Client& c) s.setNewPeerCallback(newPeerCallback); if (!s.isStarted()) { - s.start(); + s.start(isServiceGlib); } - c.start(); + c.start(isClientGlib); FileDescriptor peerFD = peerFDLatch.get(TIMEOUT); s.setNewPeerCallback(nullptr); @@ -170,66 +169,16 @@ FileDescriptor connect(Service& s, Client& c) return peerFD; } -#if GLIB_CHECK_VERSION(2,36,0) - -std::pair connectServiceGSource(Service& s, Client& c) +FileDescriptor connectServiceGSource(Service& s, Client& c) { - ValueLatch peerFDLatch; - IPCGSource::Pointer ipcGSourcePtr = IPCGSource::create(s.getFDs(), std::bind(&Service::handle, &s, _1, _2)); - - auto newPeerCallback = [&peerFDLatch, ipcGSourcePtr](const FileDescriptor newFD) { - if (ipcGSourcePtr) { - //TODO: Remove this if - ipcGSourcePtr->addFD(newFD); - } - peerFDLatch.set(newFD); - }; - - - s.setNewPeerCallback(newPeerCallback); - s.setRemovedPeerCallback(std::bind(&IPCGSource::removeFD, ipcGSourcePtr, _1)); - s.start(true); - // Service starts to process - ipcGSourcePtr->attach(); - - c.start(); - - FileDescriptor peerFD = peerFDLatch.get(TIMEOUT); - s.setNewPeerCallback(nullptr); - BOOST_REQUIRE_NE(peerFD, 0); - return std::make_pair(peerFD, ipcGSourcePtr); + return connect(s, c, true, false); } -std::pair connectClientGSource(Service& s, Client& c) +FileDescriptor connectClientGSource(Service& s, Client& c) { - // Connects the Client to the Service and returns Clients FileDescriptor - ValueLatch peerFDLatch; - auto newPeerCallback = [&peerFDLatch](const FileDescriptor newFD) { - peerFDLatch.set(newFD); - }; - s.setNewPeerCallback(newPeerCallback); - - if (!s.isStarted()) { - // Service starts to process - s.start(); - } - - - c.start(true); - IPCGSource::Pointer ipcGSourcePtr = IPCGSource::create(c.getFDs(), - std::bind(&Client::handle, &c, _1, _2)); - - ipcGSourcePtr->attach(); - - FileDescriptor peerFD = peerFDLatch.get(TIMEOUT); - s.setNewPeerCallback(nullptr); - BOOST_REQUIRE_NE(peerFD, 0); - return std::make_pair(peerFD, ipcGSourcePtr); + return connect(s, c, false, true); } -#endif // GLIB_CHECK_VERSION - - void testEcho(Client& c, const MethodID methodID) { std::shared_ptr sentData(new SendData(34)); @@ -260,13 +209,13 @@ BOOST_AUTO_TEST_CASE(ConstructorDestructor) BOOST_AUTO_TEST_CASE(ServiceAddRemoveMethod) { Service s(socketPath); - s.addMethodHandler(1, returnEmptyCallback); - s.addMethodHandler(1, returnDataCallback); + s.setMethodHandler(1, returnEmptyCallback); + s.setMethodHandler(1, returnDataCallback); s.start(); - s.addMethodHandler(1, echoCallback); - s.addMethodHandler(2, returnDataCallback); + s.setMethodHandler(1, echoCallback); + s.setMethodHandler(2, returnDataCallback); Client c(socketPath); connect(s, c); @@ -282,13 +231,13 @@ BOOST_AUTO_TEST_CASE(ClientAddRemoveMethod) { Service s(socketPath); Client c(socketPath); - c.addMethodHandler(1, returnEmptyCallback); - c.addMethodHandler(1, returnDataCallback); + c.setMethodHandler(1, returnEmptyCallback); + c.setMethodHandler(1, returnDataCallback); FileDescriptor peerFD = connect(s, c); - c.addMethodHandler(1, echoCallback); - c.addMethodHandler(2, returnDataCallback); + c.setMethodHandler(1, echoCallback); + c.setMethodHandler(2, returnDataCallback); testEcho(s, 1, peerFD); @@ -302,7 +251,7 @@ BOOST_AUTO_TEST_CASE(ServiceStartStop) { Service s(socketPath); - s.addMethodHandler(1, returnDataCallback); + s.setMethodHandler(1, returnDataCallback); s.start(); s.stop(); @@ -317,7 +266,7 @@ BOOST_AUTO_TEST_CASE(ClientStartStop) { Service s(socketPath); Client c(socketPath); - c.addMethodHandler(1, returnDataCallback); + c.setMethodHandler(1, returnDataCallback); c.start(); c.stop(); @@ -334,8 +283,8 @@ BOOST_AUTO_TEST_CASE(ClientStartStop) BOOST_AUTO_TEST_CASE(SyncClientToServiceEcho) { Service s(socketPath); - s.addMethodHandler(1, echoCallback); - s.addMethodHandler(2, echoCallback); + s.setMethodHandler(1, echoCallback); + s.setMethodHandler(2, echoCallback); Client c(socketPath); connect(s, c); @@ -347,9 +296,9 @@ BOOST_AUTO_TEST_CASE(SyncClientToServiceEcho) BOOST_AUTO_TEST_CASE(Restart) { Service s(socketPath); - s.addMethodHandler(1, echoCallback); + s.setMethodHandler(1, echoCallback); s.start(); - s.addMethodHandler(2, echoCallback); + s.setMethodHandler(2, echoCallback); Client c(socketPath); c.start(); @@ -373,7 +322,7 @@ BOOST_AUTO_TEST_CASE(SyncServiceToClientEcho) { Service s(socketPath); Client c(socketPath); - c.addMethodHandler(1, echoCallback); + c.setMethodHandler(1, echoCallback); FileDescriptor peerFD = connect(s, c); std::shared_ptr sentData(new SendData(56)); @@ -389,7 +338,7 @@ BOOST_AUTO_TEST_CASE(AsyncClientToServiceEcho) // Setup Service and Client Service s(socketPath); - s.addMethodHandler(1, echoCallback); + s.setMethodHandler(1, echoCallback); s.start(); Client c(socketPath); c.start(); @@ -414,7 +363,7 @@ BOOST_AUTO_TEST_CASE(AsyncServiceToClientEcho) Service s(socketPath); Client c(socketPath); - c.addMethodHandler(1, echoCallback); + c.setMethodHandler(1, echoCallback); FileDescriptor peerFD = connect(s, c); // Async call @@ -435,7 +384,7 @@ BOOST_AUTO_TEST_CASE(AsyncServiceToClientEcho) BOOST_AUTO_TEST_CASE(SyncTimeout) { Service s(socketPath); - s.addMethodHandler(1, longEchoCallback); + s.setMethodHandler(1, longEchoCallback); Client c(socketPath); connect(s, c); @@ -447,7 +396,7 @@ BOOST_AUTO_TEST_CASE(SyncTimeout) BOOST_AUTO_TEST_CASE(SerializationError) { Service s(socketPath); - s.addMethodHandler(1, echoCallback); + s.setMethodHandler(1, echoCallback); Client c(socketPath); connect(s, c); @@ -461,7 +410,7 @@ BOOST_AUTO_TEST_CASE(SerializationError) BOOST_AUTO_TEST_CASE(ParseError) { Service s(socketPath); - s.addMethodHandler(1, echoCallback); + s.setMethodHandler(1, echoCallback); s.start(); Client c(socketPath); @@ -481,7 +430,7 @@ BOOST_AUTO_TEST_CASE(DisconnectedPeerError) }; // Method will throw during serialization and disconnect automatically - s.addMethodHandler(1, method); + s.setMethodHandler(1, method); s.start(); Client c(socketPath); @@ -510,7 +459,7 @@ BOOST_AUTO_TEST_CASE(ReadTimeout) auto longEchoCallback = [](const FileDescriptor, std::shared_ptr& data) { return std::shared_ptr(new LongSendData(data->intVal, LONG_OPERATION_TIME)); }; - s.addMethodHandler(1, longEchoCallback); + s.setMethodHandler(1, longEchoCallback); Client c(socketPath); connect(s, c); @@ -524,7 +473,7 @@ BOOST_AUTO_TEST_CASE(ReadTimeout) BOOST_AUTO_TEST_CASE(WriteTimeout) { Service s(socketPath); - s.addMethodHandler(1, echoCallback); + s.setMethodHandler(1, echoCallback); s.start(); Client c(socketPath); @@ -559,8 +508,8 @@ BOOST_AUTO_TEST_CASE(AddSignalInRuntime) latchB.set(); }; - c.addSignalHandler(1, handlerA); - c.addSignalHandler(2, handlerB); + c.setSignalHandler(1, handlerA); + c.setSignalHandler(2, handlerB); // Wait for the signals to propagate to the Service std::this_thread::sleep_for(std::chrono::milliseconds(2 * TIMEOUT)); @@ -590,8 +539,8 @@ BOOST_AUTO_TEST_CASE(AddSignalOffline) latchB.set(); }; - c.addSignalHandler(1, handlerA); - c.addSignalHandler(2, handlerB); + c.setSignalHandler(1, handlerA); + c.setSignalHandler(2, handlerB); connect(s, c); @@ -606,9 +555,6 @@ BOOST_AUTO_TEST_CASE(AddSignalOffline) } -#if GLIB_CHECK_VERSION(2,36,0) - -// FIXME This test causes segfault, however it should work in GDB. BOOST_AUTO_TEST_CASE(ServiceGSource) { utils::Latch l; @@ -620,13 +566,12 @@ BOOST_AUTO_TEST_CASE(ServiceGSource) IPCGSource::Pointer serviceGSource; Service s(socketPath); - s.addMethodHandler(1, echoCallback); + s.setMethodHandler(1, echoCallback); Client c(socketPath); - s.addSignalHandler(2, signalHandler); + s.setSignalHandler(2, signalHandler); - auto ret = connectServiceGSource(s, c); - serviceGSource = ret.second; + connectServiceGSource(s, c); testEcho(c, 1); @@ -636,6 +581,7 @@ BOOST_AUTO_TEST_CASE(ServiceGSource) BOOST_CHECK(l.wait(TIMEOUT)); } + BOOST_AUTO_TEST_CASE(ClientGSource) { utils::Latch l; @@ -650,12 +596,10 @@ BOOST_AUTO_TEST_CASE(ClientGSource) IPCGSource::Pointer clientGSource; Client c(socketPath); - c.addMethodHandler(1, echoCallback); - c.addSignalHandler(2, signalHandler); + c.setMethodHandler(1, echoCallback); + c.setSignalHandler(2, signalHandler); - auto ret = connectClientGSource(s, c); - FileDescriptor peerFD = ret.first; - clientGSource = ret.second; + FileDescriptor peerFD = connectClientGSource(s, c); testEcho(s, 1, peerFD); @@ -665,8 +609,6 @@ BOOST_AUTO_TEST_CASE(ClientGSource) BOOST_CHECK(l.wait(TIMEOUT)); } -#endif // GLIB_CHECK_VERSION - // BOOST_AUTO_TEST_CASE(ConnectionLimitTest) // { // unsigned oldLimit = ipc::getMaxFDNumber(); @@ -674,7 +616,7 @@ BOOST_AUTO_TEST_CASE(ClientGSource) // // Setup Service and many Clients // Service s(socketPath); -// s.addMethodHandler(1, echoCallback); +// s.setMethodHandler(1, echoCallback); // s.start(); // std::list clients;