IVGCVSW-4163 Enhance the error handling in the ReadPacket function

* Introduced armnn::SocketConnectionException with fields error no and socket info.

Signed-off-by: Sadik Armagan <sadik.armagan@arm.com>
Change-Id: Ideb85b00771864e332226635aeff3096fbea8e5f
diff --git a/Android.mk b/Android.mk
index e29f0f9..c63022c 100644
--- a/Android.mk
+++ b/Android.mk
@@ -9,6 +9,7 @@
 OPENCL_HEADER_PATH := $(LOCAL_PATH)/../clframework/include
 NN_HEADER_PATH := $(LOCAL_PATH)/../../../../frameworks/ml/nn/runtime/include
 ARMNN_HEADER_PATH := $(LOCAL_PATH)/include
+ARMNN_PROFILING_INCLUDE_PATH := $(LOCAL_PATH)/profiling
 ARMNN_MAIN_HEADER_PATH := $(LOCAL_PATH)/src
 ARMNN_SOURCE_HEADER_PATH := $(LOCAL_PATH)/src/armnn
 ARMNN_SOURCE_UTILS_HEADER_PATH := $(LOCAL_PATH)/src/armnnUtils
@@ -64,6 +65,7 @@
 LOCAL_EXPORT_C_INCLUDES := \
         $(ARMNN_MAIN_HEADER_PATH) \
         $(ARMNN_SOURCE_HEADER_PATH) \
+        $(ARMNN_PROFILING_INCLUDE_PATH) \
         $(ARMNN_SOURCE_UTILS_HEADER_PATH) \
         $(ARMNN_PROFILING_HEADER_PATH) \
         $(ARMNN_BACKENDS_HEADER_PATH)
@@ -72,6 +74,7 @@
         $(OPENCL_HEADER_PATH) \
         $(NN_HEADER_PATH) \
         $(ARMNN_HEADER_PATH) \
+        $(ARMNN_PROFILING_INCLUDE_PATH) \
         $(ARMNN_MAIN_HEADER_PATH) \
         $(ARMNN_SOURCE_HEADER_PATH) \
         $(ARMNN_SOURCE_UTILS_HEADER_PATH) \
@@ -290,6 +293,7 @@
         $(OPENCL_HEADER_PATH) \
         $(NN_HEADER_PATH) \
         $(ARMNN_HEADER_PATH) \
+        $(ARMNN_PROFILING_INCLUDE_PATH) \
         $(ARMNN_MAIN_HEADER_PATH) \
         $(ARMNN_SOURCE_HEADER_PATH) \
         $(ARMNN_SOURCE_UTILS_HEADER_PATH) \
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6ab89a4..e3b794a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -247,6 +247,7 @@
     include/armnn/Version.hpp
     include/armnn/profiling/IProfilingGuidGenerator.hpp
     include/armnn/profiling/ISendTimelinePacket.hpp
+    profiling/common/include/SocketConnectionException.hpp
     src/armnn/layers/LayerCloneBase.hpp
     src/armnn/layers/LayerWithParameters.hpp
     src/armnn/layers/ActivationLayer.hpp
diff --git a/cmake/GlobalConfig.cmake b/cmake/GlobalConfig.cmake
index 8e3b68d..1fb86e9 100644
--- a/cmake/GlobalConfig.cmake
+++ b/cmake/GlobalConfig.cmake
@@ -209,6 +209,7 @@
 endif()
 
 include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/profiling)
 
 # ARM Compute
 # Note that ARM Compute has a different folder layout depending on the branch but also on
diff --git a/profiling/common/include/SocketConnectionException.hpp b/profiling/common/include/SocketConnectionException.hpp
new file mode 100644
index 0000000..58b8a14
--- /dev/null
+++ b/profiling/common/include/SocketConnectionException.hpp
@@ -0,0 +1,51 @@
+//
+// Copyright © 2020 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+#pragma once
+
+#include <sstream>
+#include <stdexcept>
+#include <string>
+
+namespace armnnProfiling
+{
+
+/// Socket Connection Exception for profiling
+class SocketConnectionException : public std::exception
+{
+public:
+    explicit SocketConnectionException(const std::string& message, int socket)
+    : m_Message(message), m_Socket(socket), m_ErrNo(-1)
+    {};
+
+    explicit SocketConnectionException(const std::string& message, int socket, int errNo)
+    : m_Message(message), m_Socket(socket), m_ErrNo(errNo)
+    {};
+
+    /// @return - Error message of  SocketProfilingConnection
+    virtual const char* what() const noexcept override
+    {
+        return m_Message.c_str();
+    }
+
+    /// @return - Socket File Descriptor of SocketProfilingConnection
+    ///           or '-1', an invalid file descriptor
+    int GetSocketFd() const noexcept
+    {
+        return m_Socket;
+    }
+
+    /// @return - errno of SocketProfilingConnection
+    int GetErrorNo() const noexcept
+    {
+        return m_ErrNo;
+    }
+
+private:
+    std::string m_Message;
+    int m_Socket;
+    int m_ErrNo;
+};
+
+} // namespace armnnProfiling
diff --git a/src/profiling/ProfilingService.cpp b/src/profiling/ProfilingService.cpp
index 0c33ca0..f111de1 100644
--- a/src/profiling/ProfilingService.cpp
+++ b/src/profiling/ProfilingService.cpp
@@ -7,6 +7,7 @@
 
 #include <armnn/BackendId.hpp>
 #include <armnn/Logging.hpp>
+#include <common/include/SocketConnectionException.hpp>
 
 #include <boost/format.hpp>
 
@@ -128,6 +129,11 @@
             ARMNN_LOG(warning) << "An error has occurred when creating the profiling connection: "
                                        << e.what();
         }
+        catch (const armnnProfiling::SocketConnectionException& e)
+        {
+            ARMNN_LOG(warning) << "An error has occurred when creating the profiling connection ["
+                                       << e.what() << "] on socket [" << e.GetSocketFd() << "].";
+        }
 
         // Move to the next state
         m_StateMachine.TransitionToState(m_ProfilingConnection
diff --git a/src/profiling/SocketProfilingConnection.cpp b/src/profiling/SocketProfilingConnection.cpp
index 4bbbc29..31f930b 100644
--- a/src/profiling/SocketProfilingConnection.cpp
+++ b/src/profiling/SocketProfilingConnection.cpp
@@ -5,6 +5,8 @@
 
 #include "SocketProfilingConnection.hpp"
 
+#include "common/include/SocketConnectionException.hpp"
+
 #include <cerrno>
 #include <fcntl.h>
 #include <string>
@@ -24,7 +26,10 @@
     m_Socket[0].fd = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
     if (m_Socket[0].fd == -1)
     {
-        throw armnn::RuntimeException(std::string("Socket construction failed: ") + strerror(errno));
+        throw armnnProfiling::SocketConnectionException(
+            std::string("SocketProfilingConnection: Socket construction failed: ")  + strerror(errno),
+            m_Socket[0].fd,
+            errno);
     }
 
     // Connect to the named unix domain socket.
@@ -36,7 +41,10 @@
     if (0 != connect(m_Socket[0].fd, reinterpret_cast<const sockaddr*>(&server), sizeof(sockaddr_un)))
     {
         Close();
-        throw armnn::RuntimeException(std::string("Cannot connect to stream socket: ") + strerror(errno));
+        throw armnnProfiling::SocketConnectionException(
+            std::string("SocketProfilingConnection: Cannot connect to stream socket: ")  + strerror(errno),
+            m_Socket[0].fd,
+            errno);
     }
 
     // Our socket will only be interested in polling reads.
@@ -46,7 +54,10 @@
     if (!Sockets::SetNonBlocking(m_Socket[0].fd))
     {
         Close();
-        throw armnn::RuntimeException(std::string("Failed to set socket as non blocking: ") + strerror(errno));
+        throw armnnProfiling::SocketConnectionException(
+            std::string("SocketProfilingConnection: Failed to set socket as non blocking: ")  + strerror(errno),
+            m_Socket[0].fd,
+            errno);
     }
 }
 
@@ -59,7 +70,10 @@
 {
     if (Sockets::Close(m_Socket[0].fd) != 0)
     {
-        throw armnn::RuntimeException(std::string("Cannot close stream socket: ") + strerror(errno));
+        throw armnnProfiling::SocketConnectionException(
+            std::string("SocketProfilingConnection: Cannot close stream socket: ")  + strerror(errno),
+            m_Socket[0].fd,
+            errno);
     }
 
     memset(m_Socket, 0, sizeof(m_Socket));
@@ -92,10 +106,13 @@
     switch (pollResult)
     {
     case -1: // Error
-        throw armnn::RuntimeException(std::string("Read failure from socket: ") + strerror(errno));
+        throw armnnProfiling::SocketConnectionException(
+            std::string("SocketProfilingConnection: Error occured while reading from socket: ") + strerror(errno),
+            m_Socket[0].fd,
+            errno);
 
     case 0: // Timeout
-        throw TimeoutException("Timeout while reading from socket");
+        throw TimeoutException("SocketProfilingConnection: Timeout while reading from socket");
 
     default: // Normal poll return but it could still contain an error signal
         // Check if the socket reported an error
@@ -105,18 +122,26 @@
             {
                 // This is an unrecoverable error.
                 Close();
-                throw armnn::RuntimeException(std::string("Error while polling receiving socket: POLLNVAL"));
+                throw armnnProfiling::SocketConnectionException(
+                    std::string("SocketProfilingConnection: Error occured while polling receiving socket: POLLNVAL."),
+                    m_Socket[0].fd);
             }
             if (m_Socket[0].revents == POLLERR)
             {
-                throw armnn::RuntimeException(std::string("Error while polling receiving socket: POLLERR: ") +
-                                              strerror(errno));
+                throw armnnProfiling::SocketConnectionException(
+                    std::string(
+                        "SocketProfilingConnection: Error occured while polling receiving socket: POLLERR: ")
+                        + strerror(errno),
+                    m_Socket[0].fd,
+                    errno);
             }
             if (m_Socket[0].revents == POLLHUP)
             {
                 // This is an unrecoverable error.
                 Close();
-                throw armnn::RuntimeException(std::string("Connection closed by remote client: POLLHUP"));
+                throw armnnProfiling::SocketConnectionException(
+                    std::string("SocketProfilingConnection: Connection closed by remote client: POLLHUP."),
+                    m_Socket[0].fd);
             }
         }
 
@@ -125,7 +150,8 @@
         {
             // This is a corner case. The socket as been woken up but not with any data.
             // We'll throw a timeout exception to loop around again.
-            throw armnn::TimeoutException("File descriptor was polled but no data was available to receive.");
+            throw armnn::TimeoutException(
+                "SocketProfilingConnection: File descriptor was polled but no data was available to receive.");
         }
 
         return ReceivePacket();
@@ -142,15 +168,23 @@
         case 0:
             // Socket has closed.
             Close();
-            throw armnn::RuntimeException("Remote socket has closed the connection.");
+            throw armnnProfiling::SocketConnectionException(
+                std::string("SocketProfilingConnection: Remote socket has closed the connection."),
+                m_Socket[0].fd);
         case -1:
             // There's been a socket error. We will presume it's unrecoverable.
             Close();
-            throw armnn::RuntimeException(std::string("Error occured on recv: ") + strerror(errno));
+            throw armnnProfiling::SocketConnectionException(
+                std::string("SocketProfilingConnection: Error occured while reading the packet: ") + strerror(errno),
+                m_Socket[0].fd,
+                errno);
         default:
             if (receiveResult < 8)
             {
-                throw armnn::RuntimeException("The received packet did not contains a valid MIPE header");
+                 throw armnnProfiling::SocketConnectionException(
+                     std::string(
+                         "SocketProfilingConnection: The received packet did not contains a valid PIPE header."),
+                     m_Socket[0].fd);
             }
             break;
     }
@@ -170,12 +204,17 @@
         long receivedLength = Sockets::Read(m_Socket[0].fd, packetData.get(), dataLength);
         if (receivedLength < 0)
         {
-            throw armnn::RuntimeException(std::string("Error occurred on recv: ") + strerror(errno));
+            throw armnnProfiling::SocketConnectionException(
+                std::string("SocketProfilingConnection: Error occured while reading the packet: ")  + strerror(errno),
+                m_Socket[0].fd,
+                errno);
         }
         if (dataLength != static_cast<uint32_t>(receivedLength))
         {
             // What do we do here if we can't read in a full packet?
-            throw armnn::RuntimeException("Invalid MIPE packet");
+            throw armnnProfiling::SocketConnectionException(
+                std::string("SocketProfilingConnection: Invalid PIPE packet."),
+                m_Socket[0].fd);
         }
     }
 
diff --git a/src/profiling/test/ProfilingTests.cpp b/src/profiling/test/ProfilingTests.cpp
index 6c1e84b..3dab93d 100644
--- a/src/profiling/test/ProfilingTests.cpp
+++ b/src/profiling/test/ProfilingTests.cpp
@@ -9,6 +9,7 @@
 #include <CommandHandler.hpp>
 #include <CommandHandlerKey.hpp>
 #include <CommandHandlerRegistry.hpp>
+#include <common/include/SocketConnectionException.hpp>
 #include <ConnectionAcknowledgedCommandHandler.hpp>
 #include <CounterDirectory.hpp>
 #include <CounterIdMap.hpp>
@@ -1888,10 +1889,25 @@
     BOOST_CHECK_THROW(differentCommandHandler(packetB), armnn::Exception);
 }
 
-BOOST_AUTO_TEST_CASE(CheckSocketProfilingConnection)
+BOOST_AUTO_TEST_CASE(CheckSocketConnectionException)
 {
-    // Check that creating a SocketProfilingConnection results in an exception as the Gator UDS doesn't exist.
-    BOOST_CHECK_THROW(new SocketProfilingConnection(), armnn::Exception);
+    // Check that creating a SocketProfilingConnection armnnProfiling in an exception as the Gator UDS doesn't exist.
+    BOOST_CHECK_THROW(new SocketProfilingConnection(), armnnProfiling::SocketConnectionException);
+}
+
+BOOST_AUTO_TEST_CASE(CheckSocketConnectionException2)
+{
+    try
+    {
+        new SocketProfilingConnection();
+    }
+    catch (armnnProfiling::SocketConnectionException& ex)
+    {
+        BOOST_CHECK(ex.GetSocketFd() == 0);
+        BOOST_CHECK(ex.GetErrorNo() == 111);
+        BOOST_CHECK(ex.what()
+                    == std::string("SocketProfilingConnection: Cannot connect to stream socket: Connection refused"));
+    }
 }
 
 BOOST_AUTO_TEST_CASE(SwTraceIsValidCharTest)