1 #include "sol_manager.hpp"
2 
3 #include "main.hpp"
4 #include "sol_context.hpp"
5 
6 #include <sys/socket.h>
7 #include <sys/un.h>
8 
9 #include <boost/asio/basic_stream_socket.hpp>
10 #include <boost/asio/io_context.hpp>
11 #include <boost/asio/local/stream_protocol.hpp>
12 #include <boost/asio/write.hpp>
13 #include <chrono>
14 #include <cmath>
15 #include <phosphor-logging/log.hpp>
16 
17 namespace sol
18 {
19 
20 using namespace phosphor::logging;
21 
22 void Manager::initConsoleSocket()
23 {
24     // explicit length constructor for NUL-prefixed abstract path
25     std::string path(CONSOLE_SOCKET_PATH, CONSOLE_SOCKET_PATH_LEN);
26     boost::asio::local::stream_protocol::endpoint ep(path);
27     consoleSocket =
28         std::make_unique<boost::asio::local::stream_protocol::socket>(*io);
29     consoleSocket->connect(ep);
30 }
31 
32 void Manager::consoleInputHandler()
33 {
34     boost::system::error_code ec;
35     boost::asio::socket_base::bytes_readable cmd(true);
36     consoleSocket->io_control(cmd, ec);
37     size_t readSize;
38     if (!ec)
39     {
40         readSize = cmd.get();
41     }
42     else
43     {
44         log<level::ERR>("Reading ready count from host console socket failed:",
45                         entry("EXCEPTION=%s", ec.message().c_str()));
46         return;
47     }
48     std::vector<uint8_t> buffer(readSize);
49     ec.clear();
50     size_t readDataLen =
51         consoleSocket->read_some(boost::asio::buffer(buffer), ec);
52     if (ec)
53     {
54         log<level::ERR>("Reading from host console socket failed:",
55                         entry("EXCEPTION=%s", ec.message().c_str()));
56         return;
57     }
58 
59     // Update the Console buffer with data read from the socket
60     buffer.resize(readDataLen);
61     dataBuffer.write(buffer);
62 }
63 
64 int Manager::writeConsoleSocket(const std::vector<uint8_t>& input) const
65 {
66     boost::system::error_code ec;
67     boost::asio::write(*consoleSocket, boost::asio::buffer(input), ec);
68     return ec.value();
69 }
70 
71 void Manager::startHostConsole()
72 {
73     if (!consoleSocket)
74     {
75         initConsoleSocket();
76     }
77     consoleSocket->async_wait(boost::asio::socket_base::wait_read,
78                               [this](const boost::system::error_code& ec) {
79                                   if (!ec)
80                                   {
81                                       consoleInputHandler();
82                                       startHostConsole();
83                                   }
84                               });
85 }
86 
87 void Manager::stopHostConsole()
88 {
89     if (consoleSocket)
90     {
91         consoleSocket->cancel();
92         consoleSocket.reset();
93     }
94 }
95 
96 void Manager::startPayloadInstance(uint8_t payloadInstance,
97                                    session::SessionID sessionID)
98 {
99     if (payloadMap.empty())
100     {
101         startHostConsole();
102     }
103 
104     // Create the SOL Context data for payload instance
105     auto context = std::make_unique<Context>(io, retryCount, sendThreshold,
106                                              payloadInstance, sessionID);
107 
108     payloadMap.emplace(payloadInstance, std::move(context));
109 }
110 
111 void Manager::stopPayloadInstance(uint8_t payloadInstance)
112 {
113     auto iter = payloadMap.find(payloadInstance);
114     if (iter == payloadMap.end())
115     {
116         throw std::runtime_error("SOL Payload instance not found ");
117     }
118 
119     payloadMap.erase(iter);
120 
121     if (payloadMap.empty())
122     {
123         stopHostConsole();
124 
125         dataBuffer.erase(dataBuffer.size());
126     }
127 }
128 
129 } // namespace sol
130