From 7e4a651799df95e44b4c99825adf18a8ef878f52 Mon Sep 17 00:00:00 2001 From: Vernon Mauery Date: Fri, 9 Nov 2018 08:43:36 -0800 Subject: 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 --- main.cpp | 2 +- sd_event_loop.cpp | 83 ---------------------------------- sd_event_loop.hpp | 12 ----- sol/sol_manager.cpp | 128 ++++++++++++++++++++++++++-------------------------- sol/sol_manager.hpp | 53 ++++++++++------------ 5 files changed, 87 insertions(+), 191 deletions(-) diff --git a/main.cpp b/main.cpp index abb7958..1e35b9a 100644 --- a/main.cpp +++ b/main.cpp @@ -29,7 +29,7 @@ static auto io = std::make_shared(); session::Manager manager; command::Table table; eventloop::EventLoop loop(io); -sol::Manager solManager; +sol::Manager solManager(io); std::tuple diff --git a/sd_event_loop.cpp b/sd_event_loop.cpp index 990426f..8d24d23 100644 --- a/sd_event_loop.cpp +++ b/sd_event_loop.cpp @@ -61,50 +61,6 @@ void EventLoop::startRmcpReceive() }); } -static int consoleInputHandler(sd_event_source* es, int fd, uint32_t revents, - void* userdata) -{ - try - { - int readSize = 0; - - if (ioctl(fd, FIONREAD, &readSize) < 0) - { - log("ioctl failed for FIONREAD:", - entry("ERRNO=%d", errno)); - return 0; - } - - std::vector buffer(readSize); - auto bufferSize = buffer.size(); - ssize_t readDataLen = 0; - - readDataLen = read(fd, buffer.data(), bufferSize); - - // Update the Console buffer with data read from the socket - if (readDataLen > 0) - { - buffer.resize(readDataLen); - std::get(singletonPool).dataBuffer.write(buffer); - } - else if (readDataLen == 0) - { - log("Connection Closed for host console socket"); - } - else if (readDataLen < 0) // Error - { - log("Reading from host console socket failed:", - entry("ERRNO=%d", errno)); - } - } - catch (std::exception& e) - { - log(e.what()); - } - - return 0; -} - static int charAccTimerHandler(sd_event_source* s, uint64_t usec, void* userdata) { @@ -223,45 +179,6 @@ int EventLoop::startEventLoop() return EXIT_SUCCESS; } -void EventLoop::startHostConsole(const sol::CustomFD& fd) -{ - int rc = 0; - - if ((fd() == -1) || hostConsole.get()) - { - throw std::runtime_error("Console descriptor already added"); - } - - sd_event_source* source = nullptr; - - // Add the fd to the event loop for EPOLLIN - rc = sd_event_add_io(event, &source, fd(), EPOLLIN, consoleInputHandler, - nullptr); - if (rc < 0) - { - throw std::runtime_error("Failed to add socket descriptor"); - } - - hostConsole.reset(source); - source = nullptr; -} - -void EventLoop::stopHostConsole() -{ - if (hostConsole.get()) - { - // Disable the host console payload - int rc = sd_event_source_set_enabled(hostConsole.get(), SD_EVENT_OFF); - if (rc < 0) - { - log("Failed to disable the host console socket", - entry("RC=%d", rc)); - } - - hostConsole.reset(); - } -} - void EventLoop::startSOLPayloadInstance(uint8_t payloadInst, IntervalType accumulateInterval, IntervalType retryInterval) diff --git a/sd_event_loop.hpp b/sd_event_loop.hpp index c81218a..0d9c268 100644 --- a/sd_event_loop.hpp +++ b/sd_event_loop.hpp @@ -76,15 +76,6 @@ class EventLoop */ int startEventLoop(); - /** @brief Add host console I/O event source to the event loop. - * - * @param[in] fd - File descriptor for host console socket. - */ - void startHostConsole(const sol::CustomFD& fd); - - /** @brief Remove host console I/O event source. */ - void stopHostConsole(); - /** @brief Initialize the timers for the SOL payload instance * * This API would add the Character accumulate interval timer event @@ -145,9 +136,6 @@ class EventLoop /** @brief register the async handler for incoming udp packets */ void startRmcpReceive(); - /** @brief Event source object for host console. */ - EventSource hostConsole = nullptr; - /** @brief boost::asio io context to run with */ std::shared_ptr io; 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 #include +#include +#include +#include +#include #include #include #include @@ -15,80 +19,78 @@ namespace sol using namespace phosphor::logging; -CustomFD::~CustomFD() +void Manager::initConsoleSocket() { - if (fd >= 0) - { - // Remove the host console descriptor from the sd_event_loop - std::get(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(*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("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(); } - - 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(fd); - auto& conFD = *(consoleFD.get()); - - rc = - connect(conFD(), (struct sockaddr*)&addr, - sizeof(addr) - sizeof(addr.sun_path) + CONSOLE_SOCKET_PATH_LEN); - if (rc < 0) + else + { + log("Reading ready count from host console socket failed:", + entry("EXCEPTION=%s", ec.message().c_str())); + return; + } + std::vector buffer(readSize); + ec.clear(); + size_t readDataLen = + consoleSocket->read_some(boost::asio::buffer(buffer), ec); + if (ec) { - log("Failed to connect to host console socket address", - entry("ERRNO=%d", errno)); - consoleFD.reset(); - throw std::runtime_error("Failed to connect to console server"); + log("Reading from host console socket failed:", + entry("EXCEPTION=%s", ec.message().c_str())); + return; } + + // Update the Console buffer with data read from the socket + buffer.resize(readDataLen); + dataBuffer.write(buffer); } int Manager::writeConsoleSocket(const std::vector& 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()); - - for (pos = 0; pos < inBufferSize; pos += rc) + boost::system::error_code ec; + boost::asio::write(*consoleSocket, boost::asio::buffer(input), ec); + return ec.value(); +} + +void Manager::startHostConsole() +{ + if (!consoleSocket) { - rc = write(conFD(), inBuffer + pos, inBufferSize - pos); - if (rc <= 0) - { - if (errno == EINTR) - { - log(" Retrying to handle EINTR", - entry("ERRNO=%d", errno)); - rc = 0; - continue; - } - else - { - errVal = errno; - log("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 @@ void Manager::startPayloadInstance(uint8_t payloadInstance, { if (payloadMap.empty()) { - initHostConsoleFd(); - - // Register the fd in the sd_event_loop - std::get(singletonPool) - .startHostConsole(*(consoleFD.get())); + startHostConsole(); } // Create the SOL Context data for payload instance @@ -132,7 +130,7 @@ void Manager::stopPayloadInstance(uint8_t payloadInstance) if (payloadMap.empty()) { - consoleFD.reset(); + stopHostConsole(); dataBuffer.erase(dataBuffer.size()); } diff --git a/sol/sol_manager.hpp b/sol/sol_manager.hpp index 5a0c18c..5d96890 100644 --- a/sol/sol_manager.hpp +++ b/sol/sol_manager.hpp @@ -4,6 +4,8 @@ #include "session.hpp" #include "sol_context.hpp" +#include +#include #include #include @@ -23,32 +25,6 @@ constexpr uint8_t retryIntervalFactor = 10; using Instance = uint8_t; -/** @struct CustomFD - * - * RAII wrapper for file descriptor. - */ -struct CustomFD -{ - CustomFD(const CustomFD&) = delete; - CustomFD& operator=(const CustomFD&) = delete; - CustomFD(CustomFD&&) = delete; - CustomFD& operator=(CustomFD&&) = delete; - - CustomFD(int fd) : fd(fd) - { - } - - ~CustomFD(); - - int operator()() const - { - return fd; - } - - private: - int fd = -1; -}; - using namespace std::chrono_literals; /** @class Manager @@ -65,13 +41,20 @@ class Manager */ using SOLPayloadMap = std::map>; - Manager() = default; + Manager() = delete; ~Manager() = default; Manager(const Manager&) = delete; Manager& operator=(const Manager&) = delete; Manager(Manager&&) = default; Manager& operator=(Manager&&) = default; + Manager(std::shared_ptr io) : io(io) + { + } + + /** @brief io context to add events to */ + std::shared_ptr io; + /** @brief Host Console Buffer. */ ConsoleData dataBuffer; @@ -180,6 +163,12 @@ class Manager */ uint8_t channel = 1; + /** @brief Add host console I/O event source to the event loop. */ + void startHostConsole(); + + /** @brief Remove host console I/O event source. */ + void stopHostConsole(); + /** @brief Start a SOL payload instance. * * Starting a payload instance involves creating the context object, @@ -263,11 +252,15 @@ class Manager private: SOLPayloadMap payloadMap; - /** @brief File descriptor for the host console. */ - std::unique_ptr consoleFD = nullptr; + /** @brief Local stream socket for the host console. */ + std::unique_ptr consoleSocket = + nullptr; /** @brief Initialize the host console file descriptor. */ - void initHostConsoleFd(); + void initConsoleSocket(); + + /** @brief Handle incoming console data on the console socket */ + void consoleInputHandler(); }; } // namespace sol -- cgit v1.2.1