IPC: Pass error to return the value callback 25/30225/7
authorJan Olszak <j.olszak@samsung.com>
Wed, 12 Nov 2014 14:36:09 +0000 (15:36 +0100)
committerGerrit Code Review <gerrit@review.vlan103.tizen.org>
Mon, 17 Nov 2014 13:04:32 +0000 (05:04 -0800)
[Bug/Feature]   Return value callback takes status enum
                Peer's socket is locket when processing
                the callbacks.
[Cause]         N/A
[Solution]      N/A
[Verification]  Build, install, run tests

Change-Id: I74f30713e7c4fa6d8f35b79c2485137d1c9119c3

common/ipc/exception.hpp
common/ipc/internals/acceptor.cpp
common/ipc/internals/processor.cpp
common/ipc/internals/processor.hpp
common/ipc/service.hpp
common/ipc/types.cpp [new file with mode: 0644]
common/ipc/types.hpp
tests/unit_tests/ipc/ut-ipc.cpp

index 67d9c86..f9e8322 100644 (file)
@@ -38,7 +38,25 @@ struct IPCException: public SecurityContainersException {
     IPCException(const std::string& error) : SecurityContainersException(error) {}
 };
 
+struct IPCParsingException: public IPCException {
+    IPCParsingException(const std::string& error) : IPCException(error) {}
+};
+
+struct IPCSerializationException: public IPCException {
+    IPCSerializationException(const std::string& error) : IPCException(error) {}
+};
+
+struct IPCPeerDisconnectedException: public IPCException {
+    IPCPeerDisconnectedException(const std::string& error) : IPCException(error) {}
+};
+
+struct IPCNaughtyPeerException: public IPCException {
+    IPCNaughtyPeerException(const std::string& error) : IPCException(error) {}
+};
 
+struct IPCTimeoutException: public IPCException {
+    IPCTimeoutException(const std::string& error) : IPCException(error) {}
+};
 }
 
 
index 9738546..193da61 100644 (file)
@@ -103,7 +103,6 @@ void Acceptor::run()
             }
             LOGE("Error in poll: " << std::string(strerror(errno)));
             throw IPCException("Error in poll: " + std::string(strerror(errno)));
-            break;
         }
 
         // Check for incoming connections
index 0465574..50327c0 100644 (file)
 #include <sys/socket.h>
 #include <limits>
 
-
 namespace security_containers {
 namespace ipc {
 
+#define IGNORE_EXCEPTIONS(expr)                        \
+    try                                                \
+    {                                                  \
+        expr;                                          \
+    }                                                  \
+    catch (const std::exception& e){                   \
+        LOGE("Callback threw an error: " << e.what()); \
+    }
+
+
+
+
 const Processor::MethodID Processor::RETURN_METHOD_ID = std::numeric_limits<MethodID>::max();
 
 Processor::Processor(const PeerCallback& newPeerCallback,
@@ -98,10 +109,7 @@ Processor::PeerID Processor::addPeer(const std::shared_ptr<Socket>& socketPtr)
     {
         Lock lock(mSocketsMutex);
         peerID = getNextPeerID();
-        SocketInfo socketInfo;
-        socketInfo.peerID = peerID;
-        socketInfo.socketPtr = std::move(socketPtr);
-        mNewSockets.push(std::move(socketInfo));
+        mNewSockets.emplace(peerID, std::move(socketPtr));
     }
     LOGI("New peer added. Id: " << peerID);
     mEventQueue.send(Event::NEW_PEER);
@@ -109,13 +117,29 @@ Processor::PeerID Processor::addPeer(const std::shared_ptr<Socket>& socketPtr)
     return peerID;
 }
 
-void Processor::removePeer(PeerID peerID)
+void Processor::removePeer(const PeerID peerID, Status status)
 {
     LOGW("Removing naughty peer. ID: " << peerID);
     {
         Lock lock(mSocketsMutex);
         mSockets.erase(peerID);
     }
+
+    {
+        // Erase associated return value callbacks
+        Lock lock(mReturnCallbacksMutex);
+
+        std::shared_ptr<void> data;
+        for (auto it = mReturnCallbacks.begin(); it != mReturnCallbacks.end();) {
+            if (it->second.peerID == peerID) {
+                IGNORE_EXCEPTIONS(it->second.process(status, data));
+                it = mReturnCallbacks.erase(it);
+            } else {
+                ++it;
+            }
+        }
+    }
+
     resetPolling();
 }
 
@@ -175,6 +199,7 @@ void Processor::run()
     }
 }
 
+
 bool Processor::handleLostConnections()
 {
     std::list<PeerID> peersToRemove;
@@ -190,14 +215,10 @@ bool Processor::handleLostConnections()
             }
         }
 
-        for (const auto peerID : peersToRemove) {
-            LOGT("Removing peer. ID: " << peerID);
-            mSockets.erase(peerID);
-        }
     }
 
-    if (!peersToRemove.empty()) {
-        resetPolling();
+    for (const PeerID peerID : peersToRemove) {
+        removePeer(peerID, Status::PEER_DISCONNECTED);
     }
 
     return !peersToRemove.empty();
@@ -231,77 +252,102 @@ bool Processor::handleInput(const PeerID peerID, const Socket& socket)
     MethodID methodID;
     MessageID messageID;
     {
-        LOGI("Locking");
         Socket::Guard guard = socket.getGuard();
         socket.read(&methodID, sizeof(methodID));
         socket.read(&messageID, sizeof(messageID));
-        LOGI("Locked");
 
         if (methodID == RETURN_METHOD_ID) {
-            LOGI("Return value for messageID: " << messageID);
-            ReturnCallbacks returnCallbacks;
-            try {
-                Lock lock(mReturnCallbacksMutex);
-                LOGT("Getting the return callback");
-                returnCallbacks = std::move(mReturnCallbacks.at(messageID));
-                mReturnCallbacks.erase(messageID);
-            } catch (const std::out_of_range&) {
-                LOGW("No return callback for messageID: " << messageID);
-                return false;
-            }
+            return onReturnValue(peerID, socket, messageID);
+        } else {
+            return onRemoteCall(peerID, socket, methodID, messageID);
+        }
+    }
 
-            std::shared_ptr<void> data;
-            try {
-                LOGT("Parsing incoming return data");
-                data = returnCallbacks.parse(socket.getFD());
-            } catch (const IPCException&) {
-                removePeer(peerID);
-                return true;
-            }
+    return false;
+}
 
-            guard.unlock();
+bool Processor::onReturnValue(const PeerID peerID,
+                              const Socket& socket,
+                              const MessageID messageID)
+{
+    LOGI("Return value for messageID: " << messageID);
+    ReturnCallbacks returnCallbacks;
+    try {
+        Lock lock(mReturnCallbacksMutex);
+        LOGT("Getting the return callback");
+        returnCallbacks = std::move(mReturnCallbacks.at(messageID));
+        mReturnCallbacks.erase(messageID);
+    } catch (const std::out_of_range&) {
+        LOGW("No return callback for messageID: " << messageID);
+        removePeer(peerID, Status::NAUGHTY_PEER);
+        return true;
+    }
 
-            LOGT("Process callback for methodID: " << methodID << "; messageID: " << messageID);
-            returnCallbacks.process(data);
+    std::shared_ptr<void> data;
+    try {
+        LOGT("Parsing incoming return data");
+        data = returnCallbacks.parse(socket.getFD());
+    } catch (const std::exception& e) {
+        LOGE("Exception during parsing: " << e.what());
+        IGNORE_EXCEPTIONS(returnCallbacks.process(Status::PARSING_ERROR, data));
+        removePeer(peerID, Status::PARSING_ERROR);
+        return true;
+    }
 
-        } else {
-            LOGI("Remote call; methodID: " << methodID << " messageID: " << messageID);
-            std::shared_ptr<MethodHandlers> methodCallbacks;
-            try {
-                Lock lock(mCallsMutex);
-                methodCallbacks = mMethodsCallbacks.at(methodID);
-            } catch (const std::out_of_range&) {
-                LOGW("No method callback for methodID: " << methodID);
-                removePeer(peerID);
-                return true;
-            }
+    LOGT("Process return value callback for messageID: " << messageID);
+    IGNORE_EXCEPTIONS(returnCallbacks.process(Status::OK, data));
 
-            std::shared_ptr<void> data;
-            try {
-                LOGT("Parsing incoming data");
-                data = methodCallbacks->parse(socket.getFD());
-            } catch (const IPCException&) {
-                removePeer(peerID);
-                return true;
-            }
+    return false;
+}
 
-            guard.unlock();
-
-            LOGT("Process callback for methodID: " << methodID << "; messageID: " << messageID);
-            std::shared_ptr<void> returnData = methodCallbacks->method(data);
-
-            LOGT("Sending return data; methodID: " << methodID << "; messageID: " << messageID);
-            try {
-                // Send the call with the socket
-                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 IPCException&) {
-                removePeer(peerID);
-                return true;
-            }
-        }
+bool Processor::onRemoteCall(const PeerID peerID,
+                             const Socket& socket,
+                             const MethodID methodID,
+                             const MessageID messageID)
+{
+    LOGI("Remote call; methodID: " << methodID << " messageID: " << messageID);
+
+    std::shared_ptr<MethodHandlers> methodCallbacks;
+    try {
+        Lock lock(mCallsMutex);
+        methodCallbacks = mMethodsCallbacks.at(methodID);
+    } catch (const std::out_of_range&) {
+        LOGW("No method callback for methodID: " << methodID);
+        removePeer(peerID, Status::NAUGHTY_PEER);
+        return true;
+    }
+
+    std::shared_ptr<void> data;
+    try {
+        LOGT("Parsing incoming data");
+        data = methodCallbacks->parse(socket.getFD());
+    } catch (const std::exception& e) {
+        LOGE("Exception during parsing: " << e.what());
+        removePeer(peerID, Status::PARSING_ERROR);
+        return true;
+    }
+
+    LOGT("Process callback for methodID: " << methodID << "; messageID: " << messageID);
+    std::shared_ptr<void> returnData;
+    try {
+        returnData = methodCallbacks->method(data);
+    } catch (const std::exception& e) {
+        LOGE("Exception in method handler: " << e.what());
+        removePeer(peerID, Status::NAUGHTY_PEER);
+        return true;
+    }
+
+    LOGT("Sending return data; methodID: " << methodID << "; messageID: " << messageID);
+    try {
+        // Send the call with the socket
+        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("Exception during serialization: " << e.what());
+        removePeer(peerID, Status::SERIALIZATION_ERROR);
+        return true;
     }
 
     return false;
@@ -325,8 +371,7 @@ bool Processor::handleEvent()
 
     case Event::CALL: {
         LOGD("Event CALL");
-        handleCall();
-        return false;
+        return handleCall();
     }
 
     case Event::NEW_PEER: {
@@ -340,15 +385,16 @@ bool Processor::handleEvent()
 
             if (mSockets.size() > mMaxNumberOfPeers) {
                 LOGE("There are too many peers. I don't accept the connection with " << socketInfo.peerID);
-
+                return false;
             }
             if (mSockets.count(socketInfo.peerID) != 0) {
                 LOGE("There already was a socket for peerID: " << socketInfo.peerID);
+                return false;
             }
-            mSockets[socketInfo.peerID] = socketInfo.socketPtr;
+
+            mSockets.emplace(socketInfo.peerID, std::move(socketInfo.socketPtr));
         }
         resetPolling();
-
         if (mNewPeerCallback) {
             // Notify about the new user.
             mNewPeerCallback(socketInfo.peerID);
@@ -384,23 +430,20 @@ Processor::Call Processor::getCall()
     return call;
 }
 
-void Processor::handleCall()
+bool Processor::handleCall()
 {
-    LOGT("Handle call from another thread");
+    LOGT("Handle call (from another thread) to send a message.");
     Call call = getCall();
 
-    ReturnCallbacks returnCallbacks;
-    returnCallbacks.parse = call.parse;
-    returnCallbacks.process = call.process;
-
     std::shared_ptr<Socket> socketPtr;
     try {
-        // Get the addressee's socket
+        // Get the peer's socket
         Lock lock(mSocketsMutex);
         socketPtr = mSockets.at(call.peerID);
     } catch (const std::out_of_range&) {
         LOGE("Peer disconnected. No socket with a peerID: " << call.peerID);
-        return;
+        IGNORE_EXCEPTIONS(call.process(Status::PEER_DISCONNECTED, call.data));
+        return false;
     }
 
     MessageID messageID = getNextMessageID();
@@ -411,7 +454,9 @@ void Processor::handleCall()
         if (mReturnCallbacks.count(messageID) != 0) {
             LOGE("There already was a return callback for messageID: " << messageID);
         }
-        mReturnCallbacks[messageID] = std::move(returnCallbacks);
+        mReturnCallbacks.emplace(messageID, ReturnCallbacks(call.peerID,
+                                                            std::move(call.parse),
+                                                            std::move(call.process)));
     }
 
     try {
@@ -422,12 +467,20 @@ void Processor::handleCall()
         call.serialize(socketPtr->getFD(), call.data);
     } catch (const std::exception& e) {
         LOGE("Error during sending a message: " << e.what());
+
+        // Inform about the error
+        IGNORE_EXCEPTIONS(mReturnCallbacks[messageID].process(Status::SERIALIZATION_ERROR, call.data));
+
         {
             Lock lock(mReturnCallbacksMutex);
             mReturnCallbacks.erase(messageID);
         }
-        // TODO: User should get the error code.
+
+        removePeer(call.peerID, Status::SERIALIZATION_ERROR);
+        return true;
     }
+
+    return false;
 }
 
 } // namespace ipc
index cb14a67..3df3f9c 100644 (file)
@@ -71,6 +71,8 @@ const unsigned int DEFAULT_MAX_NUMBER_OF_PEERS = 500;
 *  - don't throw timeout if the message is already processed
 *  - naming convention or methods that just commissions the PROCESS thread to do something
 *  - removePeer API function
+*  - error handling - special message type
+*  - some mutexes may not be needed
 */
 class Processor {
 public:
@@ -214,6 +216,10 @@ private:
         ReturnCallbacks(ReturnCallbacks&&) = default;
         ReturnCallbacks& operator=(ReturnCallbacks &&) = default;
 
+        ReturnCallbacks(PeerID peerID, const ParseCallback& parse, const ResultHandler<void>::type& process)
+            : peerID(peerID), parse(parse), process(process) {}
+
+        PeerID peerID;
         ParseCallback parse;
         ResultHandler<void>::type process;
     };
@@ -225,8 +231,11 @@ private:
         SocketInfo(SocketInfo&&) = default;
         SocketInfo& operator=(SocketInfo &&) = default;
 
-        std::shared_ptr<Socket> socketPtr;
+        SocketInfo(const PeerID peerID, const std::shared_ptr<Socket>& socketPtr)
+            : peerID(peerID), socketPtr(socketPtr) {}
+
         PeerID peerID;
+        std::shared_ptr<Socket> socketPtr;
     };
 
     enum class Event : int {
@@ -268,15 +277,22 @@ private:
 
     void run();
     bool handleEvent();
-    void handleCall();
+    bool handleCall();
     bool handleLostConnections();
     bool handleInputs();
     bool handleInput(const PeerID peerID, const Socket& socket);
+    bool onReturnValue(const PeerID peerID,
+                       const Socket& socket,
+                       const MessageID messageID);
+    bool onRemoteCall(const PeerID peerID,
+                      const Socket& socket,
+                      const MethodID methodID,
+                      const MessageID messageID);
     void resetPolling();
     MessageID getNextMessageID();
     PeerID getNextPeerID();
     Call getCall();
-    void removePeer(PeerID peerID);
+    void removePeer(const PeerID peerID, Status status);
 
 };
 
@@ -352,9 +368,9 @@ void Processor::callAsync(const MethodID methodID,
         config::saveToFD<SentDataType>(fd, *std::static_pointer_cast<SentDataType>(data));
     };
 
-    call.process = [process](std::shared_ptr<void>& data)->void {
+    call.process = [process](Status status, std::shared_ptr<void>& data)->void {
         std::shared_ptr<ReceivedDataType> tmpData = std::static_pointer_cast<ReceivedDataType>(data);
-        return process(tmpData);
+        return process(status, tmpData);
     };
 
     {
@@ -387,8 +403,10 @@ std::shared_ptr<ReceivedDataType> Processor::callSync(const MethodID methodID,
     std::mutex mtx;
     std::unique_lock<std::mutex> lck(mtx);
     std::condition_variable cv;
+    Status returnStatus = ipc::Status::UNDEFINED;
 
-    auto process = [&result, &cv](std::shared_ptr<ReceivedDataType> returnedData) {
+    auto process = [&result, &cv, &returnStatus](Status status, std::shared_ptr<ReceivedDataType> returnedData) {
+        returnStatus = status;
         result = returnedData;
         cv.notify_one();
     };
@@ -399,15 +417,17 @@ std::shared_ptr<ReceivedDataType> Processor::callSync(const MethodID methodID,
                                 data,
                                 process);
 
-    auto isResultInitialized = [&result]() {
-        return static_cast<bool>(result);
+    auto isResultInitialized = [&returnStatus]() {
+        return returnStatus != ipc::Status::UNDEFINED;
     };
 
     if (!cv.wait_for(lck, std::chrono::milliseconds(timeoutMS), isResultInitialized)) {
         LOGE("Function call timeout; methodID: " << methodID);
-        throw IPCException("Function call timeout; methodID: " + std::to_string(methodID));
+        throw IPCTimeoutException("Function call timeout; methodID: " + std::to_string(methodID));
     }
 
+    throwOnError(returnStatus);
+
     return result;
 }
 
index 08f7ec9..873673d 100644 (file)
@@ -103,7 +103,7 @@ public:
     std::shared_ptr<ReceivedDataType> callSync(const MethodID methodID,
                                                const PeerID peerID,
                                                const std::shared_ptr<SentDataType>& data,
-                                               unsigned int timeoutMS);
+                                               unsigned int timeoutMS = 500);
 
     /**
      * Asynchronous method call. The return callback will be called on
@@ -140,7 +140,7 @@ template<typename SentDataType, typename ReceivedDataType>
 std::shared_ptr<ReceivedDataType> Service::callSync(const MethodID methodID,
                                                     const PeerID peerID,
                                                     const std::shared_ptr<SentDataType>& data,
-                                                    unsigned int timeoutMS = 500)
+                                                    unsigned int timeoutMS)
 {
     LOGD("Sync calling method: " << methodID << " for user: " << peerID);
     return mProcessor.callSync<SentDataType, ReceivedDataType>(methodID, peerID, data, timeoutMS);
diff --git a/common/ipc/types.cpp b/common/ipc/types.cpp
new file mode 100644 (file)
index 0000000..e0ffc5b
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+*  Copyright (c) 2014 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   Types definitions and helper functions
+ */
+
+#include "ipc/types.hpp"
+#include "logger/logger.hpp"
+
+
+namespace security_containers {
+namespace ipc {
+
+std::string toString(const Status status)
+{
+    switch (status) {
+    case Status::OK: return "No error, everything is OK";
+    case Status::PARSING_ERROR: return "Exception during reading/parsing data from the socket";
+    case Status::SERIALIZATION_ERROR: return "Exception during writing/serializing data to the socket";
+    case Status::PEER_DISCONNECTED: return "No such peer. Might got disconnected.";
+    case Status::NAUGHTY_PEER: return "Peer performed a forbidden action.";
+    case Status::UNDEFINED: return "Undefined state";
+    default: return "Unknown status";
+    }
+}
+
+void throwOnError(const Status status)
+{
+    if (status == Status::OK) {
+        return;
+    }
+
+    std::string message = toString(status);
+    LOGE(message);
+
+    switch (status) {
+    case Status::PARSING_ERROR: throw IPCParsingException(message);
+    case Status::SERIALIZATION_ERROR: throw IPCSerializationException(message);
+    case Status::PEER_DISCONNECTED: throw IPCPeerDisconnectedException(message);
+    case Status::NAUGHTY_PEER: throw IPCNaughtyPeerException(message);
+    case Status::UNDEFINED: throw IPCException(message);
+    default: return throw IPCException(message);
+    }
+}
+} // namespace ipc
+} // namespace security_containers
index 4269664..c07e504 100644 (file)
 /**
  * @file
  * @author  Jan Olszak (j.olszak@samsung.com)
- * @brief   Handler types definitions
+ * @brief   Types definitions
  */
 
 #ifndef COMMON_IPC_HANDLERS_HPP
 #define COMMON_IPC_HANDLERS_HPP
 
+#include "ipc/exception.hpp"
+
 #include <functional>
 #include <memory>
+#include <string>
 
 namespace security_containers {
 namespace ipc {
 
+enum class Status : int {
+    OK = 0,
+    PARSING_ERROR,
+    SERIALIZATION_ERROR,
+    PEER_DISCONNECTED,
+    NAUGHTY_PEER,
+    UNDEFINED
+};
+
+std::string toString(const Status status);
+void throwOnError(const Status status);
+
 template<typename SentDataType, typename ReceivedDataType>
 struct MethodHandler {
     typedef std::function<std::shared_ptr<SentDataType>(std::shared_ptr<ReceivedDataType>&)> type;
@@ -39,7 +54,7 @@ struct MethodHandler {
 
 template <typename ReceivedDataType>
 struct ResultHandler {
-    typedef std::function<void(std::shared_ptr<ReceivedDataType>&)> type;
+    typedef std::function<void(Status, std::shared_ptr<ReceivedDataType>&)> type;
 };
 
 } // namespace ipc
index 48ad1e5..ea70b45 100644 (file)
@@ -75,6 +75,21 @@ struct EmptyData {
     CONFIG_REGISTER_EMPTY
 };
 
+struct ThrowOnAcceptData {
+    template<typename Visitor>
+    void accept(Visitor)
+    {
+        LOGE("Serialization and parsing failed");
+        throw std::exception();
+    }
+    template<typename Visitor>
+    void accept(Visitor) const
+    {
+        LOGE("Const Serialization and parsing failed");
+        throw std::exception();
+    }
+};
+
 std::shared_ptr<EmptyData> returnEmptyCallback(std::shared_ptr<EmptyData>&)
 {
     return std::shared_ptr<EmptyData>(new EmptyData());
@@ -90,6 +105,12 @@ std::shared_ptr<SendData> echoCallback(std::shared_ptr<SendData>& data)
     return data;
 }
 
+std::shared_ptr<SendData> longEchoCallback(std::shared_ptr<SendData>& data)
+{
+    std::this_thread::sleep_for(std::chrono::seconds(1));
+    return data;
+}
+
 void testEcho(Client& c, const Client::MethodID methodID)
 {
     std::shared_ptr<SendData> sentData(new SendData(34));
@@ -283,7 +304,8 @@ BOOST_AUTO_TEST_CASE(AsyncClientToServiceEchoTest)
     //Async call
     std::shared_ptr<SendData> sentData(new SendData(34));
     std::shared_ptr<SendData> recvData;
-    auto dataBack = [&cv, &recvData](std::shared_ptr<SendData>& data) {
+    auto dataBack = [&cv, &recvData](ipc::Status status, std::shared_ptr<SendData>& data) {
+        BOOST_CHECK(status == ipc::Status::OK);
         recvData = data;
         cv.notify_one();
     };
@@ -324,7 +346,8 @@ BOOST_AUTO_TEST_CASE(AsyncServiceToClientEchoTest)
     std::shared_ptr<SendData> sentData(new SendData(56));
     std::shared_ptr<SendData> recvData;
 
-    auto dataBack = [&cv, &recvData](std::shared_ptr<SendData>& data) {
+    auto dataBack = [&cv, &recvData](ipc::Status status, std::shared_ptr<SendData>& data) {
+        BOOST_CHECK(status == ipc::Status::OK);
         recvData = data;
         cv.notify_one();
     };
@@ -343,15 +366,78 @@ BOOST_AUTO_TEST_CASE(AsyncServiceToClientEchoTest)
 BOOST_AUTO_TEST_CASE(SyncTimeoutTest)
 {
     Service s(socketPath);
+    s.addMethodHandler<SendData, SendData>(1, longEchoCallback);
+
+    s.start();
+    Client c(socketPath);
+    c.start();
+
+    std::shared_ptr<SendData> sentData(new SendData(78));
+
+    BOOST_CHECK_THROW((c.callSync<SendData, SendData>(1, sentData, 10)), IPCException);
+}
+
+BOOST_AUTO_TEST_CASE(SerializationErrorTest)
+{
+    Service s(socketPath);
+    s.addMethodHandler<SendData, SendData>(1, echoCallback);
+    s.start();
+
+    Client c(socketPath);
+    c.start();
+
+    std::shared_ptr<ThrowOnAcceptData> throwingData(new ThrowOnAcceptData());
+
+    BOOST_CHECK_THROW((c.callSync<ThrowOnAcceptData, SendData>(1, throwingData)), IPCSerializationException);
+
+}
+
+BOOST_AUTO_TEST_CASE(ParseErrorTest)
+{
+    Service s(socketPath);
     s.addMethodHandler<SendData, SendData>(1, echoCallback);
+    s.start();
+
+    Client c(socketPath);
+    c.start();
+
+    std::shared_ptr<SendData> sentData(new SendData(78));
+    BOOST_CHECK_THROW((c.callSync<SendData, ThrowOnAcceptData>(1, sentData, 10000)), IPCParsingException);
+}
+
+BOOST_AUTO_TEST_CASE(DisconnectedPeerErrorTest)
+{
+    Service s(socketPath);
+
+    auto method = [](std::shared_ptr<ThrowOnAcceptData>&) {
+        return std::shared_ptr<SendData>(new SendData(1));
+    };
 
+    // Method will throw during serialization and disconnect automatically
+    s.addMethodHandler<SendData, ThrowOnAcceptData>(1, method);
     s.start();
+
     Client c(socketPath);
     c.start();
 
+    std::mutex mtx;
+    std::unique_lock<std::mutex> lck(mtx);
+    std::condition_variable cv;
+    ipc::Status retStatus = ipc::Status::UNDEFINED;
+
+    auto dataBack = [&cv, &retStatus](ipc::Status status, std::shared_ptr<SendData>&) {
+        retStatus = status;
+        cv.notify_one();
+    };
+
     std::shared_ptr<SendData> sentData(new SendData(78));
+    c.callAsync<SendData, SendData>(1, sentData, dataBack);
 
-    BOOST_CHECK_THROW((c.callSync<SendData, SendData>(1, sentData, 1)), IPCException);
+    // Wait for the response
+    BOOST_CHECK(cv.wait_for(lck, std::chrono::seconds(10), [&retStatus]() {
+        return retStatus != ipc::Status::UNDEFINED;
+    }));
+    BOOST_CHECK(retStatus == ipc::Status::PEER_DISCONNECTED);
 }