netipmid: move sol console sockets to asio

Rewrite the SOL console sockets use boost::asio. This reduces code size
and ties better into the main asio io loop.

Change-Id: Ia79b9aa3fa3c7ce1ddd9b609b032160a88394f8c
Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com>
diff --git a/sol/sol_manager.cpp b/sol/sol_manager.cpp
index 859f371..fc0efe9 100644
--- a/sol/sol_manager.cpp
+++ b/sol/sol_manager.cpp
@@ -6,6 +6,10 @@
 #include <sys/socket.h>
 #include <sys/un.h>
 
+#include <boost/asio/basic_stream_socket.hpp>
+#include <boost/asio/io_context.hpp>
+#include <boost/asio/local/stream_protocol.hpp>
+#include <boost/asio/write.hpp>
 #include <chrono>
 #include <cmath>
 #include <phosphor-logging/log.hpp>
@@ -15,80 +19,78 @@
 
 using namespace phosphor::logging;
 
-CustomFD::~CustomFD()
+void Manager::initConsoleSocket()
 {
-    if (fd >= 0)
-    {
-        // Remove the host console descriptor from the sd_event_loop
-        std::get<eventloop::EventLoop&>(singletonPool).stopHostConsole();
-        close(fd);
-    }
+    // explicit length constructor for NUL-prefixed abstract path
+    std::string path(CONSOLE_SOCKET_PATH, CONSOLE_SOCKET_PATH_LEN);
+    boost::asio::local::stream_protocol::endpoint ep(path);
+    consoleSocket =
+        std::make_unique<boost::asio::local::stream_protocol::socket>(*io);
+    consoleSocket->connect(ep);
 }
 
-void Manager::initHostConsoleFd()
+void Manager::consoleInputHandler()
 {
-    struct sockaddr_un addr;
-    int rc = 0;
-    int fd = 0;
-
-    fd = socket(AF_UNIX, SOCK_STREAM, 0);
-    if (fd < 0)
+    boost::system::error_code ec;
+    boost::asio::socket_base::bytes_readable cmd(true);
+    consoleSocket->io_control(cmd, ec);
+    size_t readSize;
+    if (!ec)
     {
-        log<level::ERR>("Failed to open the host console socket",
-                        entry("ERRNO=%d", errno));
-        throw std::runtime_error("Failed to open the host console socket");
+        readSize = cmd.get();
+    }
+    else
+    {
+        log<level::ERR>("Reading ready count from host console socket failed:",
+                        entry("EXCEPTION=%s", ec.message().c_str()));
+        return;
+    }
+    std::vector<uint8_t> buffer(readSize);
+    ec.clear();
+    size_t readDataLen =
+        consoleSocket->read_some(boost::asio::buffer(buffer), ec);
+    if (ec)
+    {
+        log<level::ERR>("Reading from host console socket failed:",
+                        entry("EXCEPTION=%s", ec.message().c_str()));
+        return;
     }
 
-    memset(&addr, 0, sizeof(addr));
-    addr.sun_family = AF_UNIX;
-    memcpy(&addr.sun_path, &CONSOLE_SOCKET_PATH, CONSOLE_SOCKET_PATH_LEN);
-    consoleFD = std::make_unique<CustomFD>(fd);
-    auto& conFD = *(consoleFD.get());
-
-    rc =
-        connect(conFD(), (struct sockaddr*)&addr,
-                sizeof(addr) - sizeof(addr.sun_path) + CONSOLE_SOCKET_PATH_LEN);
-    if (rc < 0)
-    {
-        log<level::ERR>("Failed to connect to host console socket address",
-                        entry("ERRNO=%d", errno));
-        consoleFD.reset();
-        throw std::runtime_error("Failed to connect to console server");
-    }
+    // Update the Console buffer with data read from the socket
+    buffer.resize(readDataLen);
+    dataBuffer.write(buffer);
 }
 
 int Manager::writeConsoleSocket(const std::vector<uint8_t>& input) const
 {
-    auto inBuffer = input.data();
-    auto inBufferSize = input.size();
-    size_t pos = 0;
-    ssize_t rc = 0;
-    int errVal = 0;
-    auto& conFD = *(consoleFD.get());
+    boost::system::error_code ec;
+    boost::asio::write(*consoleSocket, boost::asio::buffer(input), ec);
+    return ec.value();
+}
 
-    for (pos = 0; pos < inBufferSize; pos += rc)
+void Manager::startHostConsole()
+{
+    if (!consoleSocket)
     {
-        rc = write(conFD(), inBuffer + pos, inBufferSize - pos);
-        if (rc <= 0)
-        {
-            if (errno == EINTR)
-            {
-                log<level::INFO>(" Retrying to handle EINTR",
-                                 entry("ERRNO=%d", errno));
-                rc = 0;
-                continue;
-            }
-            else
-            {
-                errVal = errno;
-                log<level::ERR>("Failed to write to host console socket",
-                                entry("ERRNO=%d", errno));
-                return -errVal;
-            }
-        }
+        initConsoleSocket();
     }
+    consoleSocket->async_wait(boost::asio::socket_base::wait_read,
+                              [this](const boost::system::error_code& ec) {
+                                  if (!ec)
+                                  {
+                                      consoleInputHandler();
+                                      startHostConsole();
+                                  }
+                              });
+}
 
-    return 0;
+void Manager::stopHostConsole()
+{
+    if (consoleSocket)
+    {
+        consoleSocket->cancel();
+        consoleSocket.reset();
+    }
 }
 
 void Manager::startPayloadInstance(uint8_t payloadInstance,
@@ -96,11 +98,7 @@
 {
     if (payloadMap.empty())
     {
-        initHostConsoleFd();
-
-        // Register the fd in the sd_event_loop
-        std::get<eventloop::EventLoop&>(singletonPool)
-            .startHostConsole(*(consoleFD.get()));
+        startHostConsole();
     }
 
     // Create the SOL Context data for payload instance
@@ -132,7 +130,7 @@
 
     if (payloadMap.empty())
     {
-        consoleFD.reset();
+        stopHostConsole();
 
         dataBuffer.erase(dataBuffer.size());
     }