IPC: Asynchronous method result sending 47/35147/5
authorJan Olszak <j.olszak@samsung.com>
Fri, 6 Feb 2015 12:13:12 +0000 (13:13 +0100)
committerJan Olszak <j.olszak@samsung.com>
Wed, 11 Feb 2015 12:57:18 +0000 (13:57 +0100)
[Bug/Feature]   N/A
[Cause]         N/A
[Solution]      N/A
[Verification]  Build, install, run tests, run tests under valgrind

Change-Id: I16cc384545c273f65c8f57f11adde61709e08bc4

common/ipc/internals/processor.cpp
common/ipc/internals/processor.hpp
common/ipc/internals/request-queue.hpp
common/ipc/internals/send-result-request.hpp [new file with mode: 0644]
common/ipc/internals/signal-request.hpp
common/ipc/method-result.cpp [new file with mode: 0644]
common/ipc/method-result.hpp [new file with mode: 0644]
common/ipc/types.hpp
tests/unit_tests/ipc/ut-ipc.cpp

index d63e490..79c1a22 100644 (file)
@@ -163,6 +163,33 @@ FileDescriptor Processor::getEventFD()
     return mRequestQueue.getFD();
 }
 
+void Processor::sendResult(const MethodID methodID,
+                           const PeerID peerID,
+                           const MessageID messageID,
+                           const std::shared_ptr<void>& data)
+{
+    auto requestPtr = std::make_shared<SendResultRequest>(methodID, peerID, messageID, data);
+    mRequestQueue.pushFront(Event::SEND_RESULT, requestPtr);
+}
+
+void Processor::sendError(const PeerID peerID,
+                          const MessageID messageID,
+                          const int errorCode,
+                          const std::string& message)
+{
+    auto data = std::make_shared<ErrorProtocolMessage>(messageID, errorCode, message);
+    signalInternal<ErrorProtocolMessage>(ERROR_METHOD_ID, peerID , data);
+}
+
+void Processor::sendVoid(const MethodID methodID,
+                         const PeerID peerID,
+                         const MessageID messageID)
+{
+    auto data = std::make_shared<EmptyData>();
+    auto requestPtr = std::make_shared<SendResultRequest>(methodID, peerID, messageID, data);
+    mRequestQueue.pushFront(Event::SEND_RESULT, requestPtr);
+}
+
 void Processor::removeMethod(const MethodID methodID)
 {
     Lock lock(mStateMutex);
@@ -374,16 +401,16 @@ bool Processor::handleInput(const FileDescriptor fd)
         return false;
     }
 
-    Socket& socket = *peerIt->socketPtr;
 
     MethodID methodID;
     MessageID messageID;
     {
-        Socket::Guard guard = socket.getGuard();
         try {
+            // Read information about the incoming data
+            Socket& socket = *peerIt->socketPtr;
+            Socket::Guard guard = socket.getGuard();
             socket.read(&methodID, sizeof(methodID));
             socket.read(&messageID, sizeof(messageID));
-
         } catch (const IPCException& e) {
             LOGE(mLogPrefix + "Error during reading the socket");
             removePeerInternal(peerIt,
@@ -525,13 +552,13 @@ bool Processor::onRemoteMethod(Peers::iterator& peerIt,
     }
 
     LOGT(mLogPrefix + "Process callback for methodID: " << methodID << "; messageID: " << messageID);
-    std::shared_ptr<void> returnData;
     try {
-        returnData = methodCallbacks->method(peerIt->peerID, data);
+        methodCallbacks->method(peerIt->peerID,
+                                data,
+                                std::make_shared<MethodResult>(*this, methodID, messageID, peerIt->peerID));
     } catch (const IPCUserException& e) {
         LOGW("User's exception");
-        auto data = std::make_shared<ErrorProtocolMessage>(messageID, e.getCode(), e.what());
-        signalInternal<ErrorProtocolMessage>(ERROR_METHOD_ID, peerIt->peerID, data);
+        sendError(peerIt->peerID, messageID, e.getCode(), e.what());
         return false;
     } catch (const std::exception& e) {
         LOGE(mLogPrefix + "Exception in method handler: " << e.what());
@@ -540,22 +567,6 @@ bool Processor::onRemoteMethod(Peers::iterator& peerIt,
         return true;
     }
 
-    LOGT(mLogPrefix + "Sending return data; methodID: " << methodID << "; messageID: " << messageID);
-    try {
-        // Send the call with the socket
-        Socket& socket = *peerIt->socketPtr;
-        Socket::Guard guard = socket.getGuard();
-        socket.write(&RETURN_METHOD_ID, sizeof(RETURN_METHOD_ID));
-        socket.write(&messageID, sizeof(messageID));
-        methodCallbacks->serialize(socket.getFD(), returnData);
-    } catch (const std::exception& e) {
-        LOGE(mLogPrefix + "Exception during serialization: " << e.what());
-        removePeerInternal(peerIt,
-                           std::make_exception_ptr(IPCSerializationException()));
-
-        return true;
-    }
-
     return false;
 }
 
@@ -573,6 +584,7 @@ bool Processor::handleEvent()
     case Event::SIGNAL:      return onSignalRequest(*request.get<SignalRequest>());
     case Event::ADD_PEER:    return onAddPeerRequest(*request.get<AddPeerRequest>());
     case Event::REMOVE_PEER: return onRemovePeerRequest(*request.get<RemovePeerRequest>());
+    case Event::SEND_RESULT: return onSendResultRequest(*request.get<SendResultRequest>());
     case Event::FINISH:      return onFinishRequest(*request.get<FinishRequest>());
     }
 
@@ -602,9 +614,9 @@ bool Processor::onMethodRequest(MethodRequest& request)
                                                                     std::move(request.parse),
                                                                     std::move(request.process)));
 
-    Socket& socket = *peerIt->socketPtr;
     try {
         // Send the call with the socket
+        Socket& socket = *peerIt->socketPtr;
         Socket::Guard guard = socket.getGuard();
         socket.write(&request.methodID, sizeof(request.methodID));
         socket.write(&request.messageID, sizeof(request.messageID));
@@ -639,9 +651,9 @@ bool Processor::onSignalRequest(SignalRequest& request)
         return false;
     }
 
-    Socket& socket = *peerIt->socketPtr;
     try {
         // Send the call with the socket
+        Socket& socket = *peerIt->socketPtr;
         Socket::Guard guard = socket.getGuard();
         socket.write(&request.methodID, sizeof(request.methodID));
         socket.write(&request.messageID, sizeof(request.messageID));
@@ -707,6 +719,51 @@ bool Processor::onRemovePeerRequest(RemovePeerRequest& request)
     return true;
 }
 
+bool Processor::onSendResultRequest(SendResultRequest& request)
+{
+    LOGS(mLogPrefix + "Processor onMethodRequest");
+
+    auto peerIt = getPeerInfoIterator(request.peerID);
+
+    if (peerIt == mPeerInfo.end()) {
+        LOGE(mLogPrefix + "Peer disconnected, no result is sent. No user with a peerID: " << request.peerID);
+        return false;
+    }
+
+    std::shared_ptr<MethodHandlers> methodCallbacks;
+    try {
+        methodCallbacks = mMethodsCallbacks.at(request.methodID);
+    } catch (const std::out_of_range&) {
+        LOGW(mLogPrefix + "No method, might have been deleted. methodID: " << request.methodID);
+        return true;
+    }
+
+    try {
+        // Send the call with the socket
+        Socket& socket = *peerIt->socketPtr;
+        Socket::Guard guard = socket.getGuard();
+        socket.write(&RETURN_METHOD_ID, sizeof(RETURN_METHOD_ID));
+        socket.write(&request.messageID, sizeof(request.messageID));
+        LOGT(mLogPrefix + "Serializing the message");
+        methodCallbacks->serialize(socket.getFD(), request.data);
+    } catch (const std::exception& e) {
+        LOGE(mLogPrefix + "Error during sending a method: " << e.what());
+
+        // Inform about the error
+        ResultBuilder resultBuilder(std::make_exception_ptr(IPCSerializationException()));
+        IGNORE_EXCEPTIONS(mReturnCallbacks[request.messageID].process(resultBuilder));
+
+
+        mReturnCallbacks.erase(request.messageID);
+        removePeerInternal(peerIt,
+                           std::make_exception_ptr(IPCSerializationException()));
+        return true;
+
+    }
+
+    return false;
+}
+
 bool Processor::onFinishRequest(FinishRequest& request)
 {
     LOGS(mLogPrefix + "Processor onFinishRequest");
@@ -727,6 +784,10 @@ bool Processor::onFinishRequest(FinishRequest& request)
             onRemovePeerRequest(*request.get<RemovePeerRequest>());
             break;
         }
+        case Event::SEND_RESULT: {
+            onSendResultRequest(*request.get<SendResultRequest>());
+            break;
+        }
         case Event::SIGNAL:
         case Event::ADD_PEER:
         case Event::FINISH:
@@ -768,6 +829,11 @@ std::ostream& operator<<(std::ostream& os, const Processor::Event& event)
         os << "Event::REMOVE_PEER";
         break;
     }
+
+    case Processor::Event::SEND_RESULT: {
+        os << "Event::SEND_RESULT";
+        break;
+    }
     }
 
     return os;
index b890cda..86a3f42 100644 (file)
 #include "ipc/internals/signal-request.hpp"
 #include "ipc/internals/add-peer-request.hpp"
 #include "ipc/internals/remove-peer-request.hpp"
+#include "ipc/internals/send-result-request.hpp"
 #include "ipc/internals/finish-request.hpp"
 #include "ipc/exception.hpp"
+#include "ipc/method-result.hpp"
 #include "ipc/types.hpp"
 #include "config/manager.hpp"
 #include "config/fields.hpp"
 #include <list>
 #include <functional>
 #include <unordered_map>
+#include <utility>
 
 namespace vasum {
 namespace ipc {
 
 const unsigned int DEFAULT_MAX_NUMBER_OF_PEERS = 500;
-
 /**
 * This class wraps communication via UX sockets
 *
@@ -89,11 +91,12 @@ const unsigned int DEFAULT_MAX_NUMBER_OF_PEERS = 500;
 class Processor {
 private:
     enum class Event {
-        FINISH,     // Shutdown request
-        METHOD,     // New method call in the queue
-        SIGNAL,     // New signal call in the queue
-        ADD_PEER,   // New peer in the queue
-        REMOVE_PEER // Remove peer
+        FINISH,      // Shutdown request
+        METHOD,      // New method call in the queue
+        SIGNAL,      // New signal call in the queue
+        ADD_PEER,    // New peer in the queue
+        REMOVE_PEER, // Remove peer
+        SEND_RESULT  // Send the result of a method's call
     };
 
 public:
@@ -209,6 +212,44 @@ public:
                           const typename SignalHandler<ReceivedDataType>::type& process);
 
     /**
+     * Send result of the method.
+     * Used for asynchronous communication, only internally.
+     *
+     * @param methodID API dependent id of the method
+     * @param peerID id of the peer
+     * @param messageID id of the message to which it replies
+     * @param data data to send
+     */
+    void sendResult(const MethodID methodID,
+                    const PeerID peerID,
+                    const MessageID messageID,
+                    const std::shared_ptr<void>& data);
+
+    /**
+     * Send error result of the method
+     *
+     * @param peerID id of the peer
+     * @param messageID id of the message to which it replies
+     * @param errorCode code of the error
+     * @param message description of the error
+     */
+    void sendError(const PeerID peerID,
+                   const MessageID messageID,
+                   const int errorCode,
+                   const std::string& message);
+
+    /**
+     * Indicate that the method handler finished
+     *
+     * @param methodID API dependent id of the method
+     * @param peerID id of the peer
+     * @param messageID id of the message to which it replies
+     */
+    void sendVoid(const MethodID methodID,
+                  const PeerID peerID,
+                  const MessageID messageID);
+
+    /**
      * Removes the callback
      *
      * @param methodID API dependent id of the method
@@ -220,7 +261,7 @@ public:
      *
      * @param methodID API dependent id of the method
      * @param peerID id of the peer
-     * @param data data to sent
+     * @param data data to send
      * @param timeoutMS how long to wait for the return value before throw
      * @tparam SentDataType data type to send
      * @tparam ReceivedDataType data type to receive
@@ -432,6 +473,7 @@ private:
     bool onSignalRequest(SignalRequest& request);
     bool onAddPeerRequest(AddPeerRequest& request);
     bool onRemovePeerRequest(RemovePeerRequest& request);
+    bool onSendResultRequest(SendResultRequest& request);
     bool onFinishRequest(FinishRequest& request);
 
     bool handleLostConnections();
@@ -480,9 +522,9 @@ void Processor::setMethodHandlerInternal(const MethodID methodID,
         config::saveToFD<SentDataType>(fd, *std::static_pointer_cast<SentDataType>(data));
     };
 
-    methodCall.method = [method](const PeerID peerID, std::shared_ptr<void>& data)->std::shared_ptr<void> {
+    methodCall.method = [method](const PeerID peerID, std::shared_ptr<void>& data, MethodResult::Pointer && methodResult) {
         std::shared_ptr<ReceivedDataType> tmpData = std::static_pointer_cast<ReceivedDataType>(data);
-        return method(peerID, tmpData);
+        method(peerID, tmpData, std::forward<MethodResult::Pointer>(methodResult));
     };
 
     mMethodsCallbacks[methodID] = std::make_shared<MethodHandlers>(std::move(methodCall));
@@ -636,8 +678,8 @@ void Processor::signalInternal(const MethodID methodID,
                                const PeerID peerID,
                                const std::shared_ptr<SentDataType>& data)
 {
-    auto request = SignalRequest::create<SentDataType>(methodID, peerID, data);
-    mRequestQueue.pushFront(Event::SIGNAL, request);
+    auto requestPtr = SignalRequest::create<SentDataType>(methodID, peerID, data);
+    mRequestQueue.pushFront(Event::SIGNAL, requestPtr);
 }
 
 template<typename SentDataType>
@@ -651,8 +693,8 @@ void Processor::signal(const MethodID methodID,
         return;
     }
     for (const PeerID peerID : it->second) {
-        auto request =  SignalRequest::create<SentDataType>(methodID, peerID, data);
-        mRequestQueue.pushBack(Event::SIGNAL, request);
+        auto requestPtr =  SignalRequest::create<SentDataType>(methodID, peerID, data);
+        mRequestQueue.pushBack(Event::SIGNAL, requestPtr);
     }
 }
 
index f648345..e1ad46b 100644 (file)
@@ -31,6 +31,7 @@
 
 #include <list>
 #include <memory>
+#include <mutex>
 #include <algorithm>
 
 namespace vasum {
@@ -70,12 +71,12 @@ public:
     /**
      * @return event's file descriptor
      */
-    int getFD() const;
+    int getFD();
 
     /**
      * @return is the queue empty
      */
-    bool isEmpty() const;
+    bool isEmpty();
 
     /**
      * Push data to back of the queue
@@ -110,19 +111,24 @@ public:
     bool removeIf(Predicate predicate);
 
 private:
+    typedef std::unique_lock<std::mutex> Lock;
+
     std::list<Request> mRequests;
+    std::mutex mStateMutex;
     EventFD mEventFD;
 };
 
 template<typename RequestIdType>
-int RequestQueue<RequestIdType>::getFD() const
+int RequestQueue<RequestIdType>::getFD()
 {
+    Lock lock(mStateMutex);
     return mEventFD.getFD();
 }
 
 template<typename RequestIdType>
-bool RequestQueue<RequestIdType>::isEmpty() const
+bool RequestQueue<RequestIdType>::isEmpty()
 {
+    Lock lock(mStateMutex);
     return mRequests.empty();
 }
 
@@ -130,6 +136,7 @@ template<typename RequestIdType>
 void RequestQueue<RequestIdType>::pushBack(const RequestIdType requestID,
                                            const std::shared_ptr<void>& data)
 {
+    Lock lock(mStateMutex);
     Request request(requestID, data);
     mRequests.push_back(std::move(request));
     mEventFD.send();
@@ -139,6 +146,7 @@ template<typename RequestIdType>
 void RequestQueue<RequestIdType>::pushFront(const RequestIdType requestID,
                                             const std::shared_ptr<void>& data)
 {
+    Lock lock(mStateMutex);
     Request request(requestID, data);
     mRequests.push_front(std::move(request));
     mEventFD.send();
@@ -147,6 +155,7 @@ void RequestQueue<RequestIdType>::pushFront(const RequestIdType requestID,
 template<typename RequestIdType>
 typename RequestQueue<RequestIdType>::Request RequestQueue<RequestIdType>::pop()
 {
+    Lock lock(mStateMutex);
     mEventFD.receive();
     if (mRequests.empty()) {
         LOGE("Request queue is empty");
@@ -161,6 +170,7 @@ template<typename RequestIdType>
 template<typename Predicate>
 bool RequestQueue<RequestIdType>::removeIf(Predicate predicate)
 {
+    Lock lock(mStateMutex);
     auto it = std::find_if(mRequests.begin(), mRequests.end(), predicate);
     if (it == mRequests.end()) {
         return false;
diff --git a/common/ipc/internals/send-result-request.hpp b/common/ipc/internals/send-result-request.hpp
new file mode 100644 (file)
index 0000000..bc1db6c
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+*  Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+*
+*  Contact: Jan Olszak <j.olszak@samsung.com>
+*
+*  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   Processor's request to send the result of a method
+ */
+
+#ifndef COMMON_IPC_INTERNALS_SEND_RESULT_REQUEST_HPP
+#define COMMON_IPC_INTERNALS_SEND_RESULT_REQUEST_HPP
+
+#include "ipc/types.hpp"
+#include "logger/logger-scope.hpp"
+
+namespace vasum {
+namespace ipc {
+
+class SendResultRequest {
+public:
+    SendResultRequest(const SendResultRequest&) = delete;
+    SendResultRequest& operator=(const SendResultRequest&) = delete;
+
+    SendResultRequest(const MethodID methodID,
+                      const PeerID peerID,
+                      const MessageID messageID,
+                      const std::shared_ptr<void>& data)
+        : methodID(methodID),
+          peerID(peerID),
+          messageID(messageID),
+          data(data)
+    {}
+
+    MethodID methodID;
+    PeerID peerID;
+    MessageID messageID;
+    std::shared_ptr<void> data;
+};
+
+} // namespace ipc
+} // namespace vasum
+
+#endif // COMMON_IPC_INTERNALS_SEND_RESULT_REQUEST_HPP
index 8a11ee8..dac9c4d 100644 (file)
@@ -37,8 +37,6 @@ public:
     SignalRequest(const SignalRequest&) = delete;
     SignalRequest& operator=(const SignalRequest&) = delete;
 
-
-
     template<typename SentDataType>
     static std::shared_ptr<SignalRequest> create(const MethodID methodID,
                                                  const PeerID peerID,
diff --git a/common/ipc/method-result.cpp b/common/ipc/method-result.cpp
new file mode 100644 (file)
index 0000000..826354c
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+*  Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+*
+*  Contact: Jan Olszak <j.olszak@samsung.com>
+*
+*  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   Class for sending the result of a method
+ */
+
+#include "config.hpp"
+
+#include "ipc/method-result.hpp"
+#include "ipc/internals/processor.hpp"
+
+namespace vasum {
+namespace ipc {
+
+MethodResult::MethodResult(Processor& processor,
+                           const MethodID methodID,
+                           const MessageID messageID,
+                           const PeerID peerID)
+    : mProcessor(processor),
+      mMethodID(methodID),
+      mPeerID(peerID),
+      mMessageID(messageID)
+{}
+
+void MethodResult::setInternal(const std::shared_ptr<void>& data)
+{
+    mProcessor.sendResult(mMethodID, mPeerID, mMessageID, data);
+}
+
+void MethodResult::setVoid()
+{
+    mProcessor.sendVoid(mMethodID, mPeerID, mMessageID);
+}
+
+void MethodResult::setError(const int code, const std::string& message)
+{
+    mProcessor.sendError(mPeerID, mMessageID, code, message);
+}
+
+} // namespace ipc
+} // namespace vasum
diff --git a/common/ipc/method-result.hpp b/common/ipc/method-result.hpp
new file mode 100644 (file)
index 0000000..ebe9697
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+*  Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+*
+*  Contact: Jan Olszak <j.olszak@samsung.com>
+*
+*  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   Class for sending the result of a method
+ */
+
+#ifndef COMMON_IPC_METHOD_RESULT_HPP
+#define COMMON_IPC_METHOD_RESULT_HPP
+
+#include "ipc/types.hpp"
+#include "logger/logger.hpp"
+#include <memory>
+
+namespace vasum {
+namespace ipc {
+
+class Processor;
+
+class MethodResult {
+public:
+    typedef std::shared_ptr<MethodResult> Pointer;
+
+    MethodResult(Processor& processor,
+                 const MethodID methodID,
+                 const MessageID messageID,
+                 const PeerID peerID);
+
+
+    template<typename Data>
+    void set(const std::shared_ptr<Data>& data)
+    {
+        setInternal(data);
+    }
+
+    void setVoid();
+    void setError(const int code, const std::string& message);
+
+private:
+    Processor& mProcessor;
+    MethodID mMethodID;
+    PeerID mPeerID;
+    MessageID mMessageID;
+
+    void setInternal(const std::shared_ptr<void>& data);
+};
+
+template<typename SentDataType, typename ReceivedDataType>
+struct MethodHandler {
+    typedef std::function < void(PeerID peerID,
+                                 std::shared_ptr<ReceivedDataType>& data,
+                                 MethodResult::Pointer&& methodResult) > type;
+};
+
+} // namespace ipc
+} // namespace vasum
+
+#endif // COMMON_IPC_METHOD_RESULT_HPP
index fe132ec..3fec337 100644 (file)
@@ -25,7 +25,6 @@
 #ifndef COMMON_IPC_TYPES_HPP
 #define COMMON_IPC_TYPES_HPP
 
-#include "ipc/exception.hpp"
 #include <functional>
 #include <memory>
 #include <string>
@@ -45,11 +44,6 @@ typedef std::function<std::shared_ptr<void>(int fd)> ParseCallback;
 MessageID getNextMessageID();
 PeerID getNextPeerID();
 
-template<typename SentDataType, typename ReceivedDataType>
-struct MethodHandler {
-    typedef std::function<std::shared_ptr<SentDataType>(PeerID peerID,
-                                                        std::shared_ptr<ReceivedDataType>& data)> type;
-};
 
 template<typename ReceivedDataType>
 struct SignalHandler {
index cb475f1..56c94cb 100644 (file)
@@ -46,6 +46,7 @@
 #include <thread>
 #include <chrono>
 #include <utility>
+#include <future>
 #include <boost/filesystem.hpp>
 
 using namespace vasum;
@@ -136,25 +137,36 @@ struct ThrowOnAcceptData {
     }
 };
 
-std::shared_ptr<EmptyData> returnEmptyCallback(const PeerID, std::shared_ptr<EmptyData>&)
+void returnEmptyCallback(const PeerID,
+                         std::shared_ptr<EmptyData>&,
+                         MethodResult::Pointer methodResult)
 {
-    return std::make_shared<EmptyData>();
+    methodResult->setVoid();
 }
 
-std::shared_ptr<SendData> returnDataCallback(const PeerID, std::shared_ptr<RecvData>&)
+void returnDataCallback(const PeerID,
+                        std::shared_ptr<RecvData>&,
+                        MethodResult::Pointer methodResult)
 {
-    return std::make_shared<SendData>(1);
+    auto returnData = std::make_shared<SendData>(1);
+    methodResult->set(returnData);
 }
 
-std::shared_ptr<SendData> echoCallback(const PeerID, std::shared_ptr<RecvData>& data)
+void echoCallback(const PeerID,
+                  std::shared_ptr<RecvData>& data,
+                  MethodResult::Pointer methodResult)
 {
-    return std::make_shared<SendData>(data->intVal);
+    auto returnData = std::make_shared<SendData>(data->intVal);
+    methodResult->set(returnData);
 }
 
-std::shared_ptr<SendData> longEchoCallback(const PeerID, std::shared_ptr<RecvData>& data)
+void longEchoCallback(const PeerID,
+                      std::shared_ptr<RecvData>& data,
+                      MethodResult::Pointer methodResult)
 {
     std::this_thread::sleep_for(std::chrono::milliseconds(LONG_OPERATION_TIME));
-    return std::make_shared<SendData>(data->intVal);
+    auto returnData = std::make_shared<SendData>(data->intVal);
+    methodResult->set(returnData);
 }
 
 PeerID connect(Service& s, Client& c, bool isServiceGlib = false, bool isClientGlib = false)
@@ -431,8 +443,9 @@ BOOST_AUTO_TEST_CASE(DisconnectedPeerError)
     ValueLatch<Result<RecvData>> retStatusLatch;
     Service s(socketPath);
 
-    auto method = [](const PeerID, std::shared_ptr<ThrowOnAcceptData>&) {
-        return std::shared_ptr<SendData>(new SendData(1));
+    auto method = [](const PeerID, std::shared_ptr<ThrowOnAcceptData>&, MethodResult::Pointer methodResult) {
+        auto resultData = std::make_shared<SendData>(1);
+        methodResult->set<SendData>(resultData);
     };
 
     // Method will throw during serialization and disconnect automatically
@@ -462,8 +475,9 @@ BOOST_AUTO_TEST_CASE(DisconnectedPeerError)
 BOOST_AUTO_TEST_CASE(ReadTimeout)
 {
     Service s(socketPath);
-    auto longEchoCallback = [](const PeerID, std::shared_ptr<RecvData>& data) {
-        return std::shared_ptr<LongSendData>(new LongSendData(data->intVal, LONG_OPERATION_TIME));
+    auto longEchoCallback = [](const PeerID, std::shared_ptr<RecvData>& data, MethodResult::Pointer methodResult) {
+        auto resultData = std::make_shared<LongSendData>(data->intVal, LONG_OPERATION_TIME);
+        methodResult->set<LongSendData>(resultData);
     };
     s.setMethodHandler<LongSendData, RecvData>(1, longEchoCallback);
 
@@ -514,7 +528,6 @@ BOOST_AUTO_TEST_CASE(AddSignalInRuntime)
         recvDataLatchB.set(data);
     };
 
-    LOGH("SETTING SIGNAAALS");
     c.setSignalHandler<RecvData>(1, handlerA);
     c.setSignalHandler<RecvData>(2, handlerB);
 
@@ -634,12 +647,18 @@ BOOST_AUTO_TEST_CASE(UsersError)
     Client c(socketPath);
     auto clientID = connect(s, c);
 
-    auto throwingMethodHandler = [&](const PeerID, std::shared_ptr<RecvData>&) -> std::shared_ptr<SendData> {
+    auto throwingMethodHandler = [&](const PeerID, std::shared_ptr<RecvData>&, MethodResult::Pointer) {
         throw IPCUserException(TEST_ERROR_CODE, TEST_ERROR_MESSAGE);
     };
 
+    auto sendErrorMethodHandler = [&](const PeerID, std::shared_ptr<RecvData>&, MethodResult::Pointer methodResult) {
+        methodResult->setError(TEST_ERROR_CODE, TEST_ERROR_MESSAGE);
+    };
+
     s.setMethodHandler<SendData, RecvData>(1, throwingMethodHandler);
+    s.setMethodHandler<SendData, RecvData>(2, sendErrorMethodHandler);
     c.setMethodHandler<SendData, RecvData>(1, throwingMethodHandler);
+    c.setMethodHandler<SendData, RecvData>(2, sendErrorMethodHandler);
 
     std::shared_ptr<SendData> sentData(new SendData(78));
 
@@ -649,8 +668,66 @@ BOOST_AUTO_TEST_CASE(UsersError)
 
     BOOST_CHECK_EXCEPTION((c.callSync<SendData, RecvData>(1, sentData, TIMEOUT)), IPCUserException, hasProperData);
     BOOST_CHECK_EXCEPTION((s.callSync<SendData, RecvData>(1, clientID, sentData, TIMEOUT)), IPCUserException, hasProperData);
+    BOOST_CHECK_EXCEPTION((c.callSync<SendData, RecvData>(2, sentData, TIMEOUT)), IPCUserException, hasProperData);
+    BOOST_CHECK_EXCEPTION((s.callSync<SendData, RecvData>(2, clientID, sentData, TIMEOUT)), IPCUserException, hasProperData);
+}
+
+BOOST_AUTO_TEST_CASE(AsyncResult)
+{
+    const int TEST_ERROR_CODE = -567;
+    const std::string TEST_ERROR_MESSAGE = "Ooo jooo!";
+
+    Service s(socketPath);
+    Client c(socketPath);
+    auto clientID = connect(s, c);
+
+    auto errorMethodHandler = [&](const PeerID, std::shared_ptr<RecvData>&, MethodResult::Pointer methodResult) {
+        std::async(std::launch::async, [&, methodResult] {
+            std::this_thread::sleep_for(std::chrono::milliseconds(SHORT_OPERATION_TIME));
+            methodResult->setError(TEST_ERROR_CODE, TEST_ERROR_MESSAGE);
+        });
+    };
+
+    auto voidMethodHandler = [&](const PeerID, std::shared_ptr<RecvData>&, MethodResult::Pointer methodResult) {
+        std::async(std::launch::async, [methodResult] {
+            std::this_thread::sleep_for(std::chrono::milliseconds(SHORT_OPERATION_TIME));
+            methodResult->setVoid();
+        });
+    };
+
+    auto dataMethodHandler = [&](const PeerID, std::shared_ptr<RecvData>& data, MethodResult::Pointer methodResult) {
+        std::async(std::launch::async, [data, methodResult] {
+            std::this_thread::sleep_for(std::chrono::milliseconds(SHORT_OPERATION_TIME));
+            methodResult->set(data);
+        });
+    };
+
+    s.setMethodHandler<SendData, RecvData>(1, errorMethodHandler);
+    s.setMethodHandler<EmptyData, RecvData>(2, voidMethodHandler);
+    s.setMethodHandler<SendData, RecvData>(3, dataMethodHandler);
+    c.setMethodHandler<SendData, RecvData>(1, errorMethodHandler);
+    c.setMethodHandler<EmptyData, RecvData>(2, voidMethodHandler);
+    c.setMethodHandler<SendData, RecvData>(3, dataMethodHandler);
+
+    std::shared_ptr<SendData> sentData(new SendData(90));
+
+    auto hasProperData = [&](const IPCUserException & e) {
+        return e.getCode() == TEST_ERROR_CODE && e.what() == TEST_ERROR_MESSAGE;
+    };
+
+    BOOST_CHECK_EXCEPTION((s.callSync<SendData, RecvData>(1, clientID, sentData, TIMEOUT)), IPCUserException, hasProperData);
+    BOOST_CHECK_EXCEPTION((c.callSync<SendData, RecvData>(1, sentData, TIMEOUT)), IPCUserException, hasProperData);
+
+    BOOST_CHECK_NO_THROW((s.callSync<SendData, EmptyData>(2, clientID, sentData, TIMEOUT)));
+    BOOST_CHECK_NO_THROW((c.callSync<SendData, EmptyData>(2, sentData, TIMEOUT)));
 
+    std::shared_ptr<RecvData> recvData;
+    recvData = s.callSync<SendData, RecvData>(3, clientID, sentData, TIMEOUT);
+    BOOST_CHECK_EQUAL(recvData->intVal, sentData->intVal);
+    recvData = c.callSync<SendData, RecvData>(3, sentData, TIMEOUT);
+    BOOST_CHECK_EQUAL(recvData->intVal, sentData->intVal);
 }
+
 // BOOST_AUTO_TEST_CASE(ConnectionLimitTest)
 // {
 //     unsigned oldLimit = ipc::getMaxFDNumber();