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 <chrono>
10 #include <cmath>
11 #include <phosphor-logging/log.hpp>
12 
13 namespace sol
14 {
15 
16 using namespace phosphor::logging;
17 
18 CustomFD::~CustomFD()
19 {
20     if (fd >= 0)
21     {
22         // Remove the host console descriptor from the sd_event_loop
23         std::get<eventloop::EventLoop&>(singletonPool).stopHostConsole();
24         close(fd);
25     }
26 }
27 
28 void Manager::initHostConsoleFd()
29 {
30     struct sockaddr_un addr;
31     int rc = 0;
32     int fd = 0;
33 
34     fd = socket(AF_UNIX, SOCK_STREAM, 0);
35     if (fd < 0)
36     {
37         log<level::ERR>("Failed to open the host console socket",
38                         entry("ERRNO=%d", errno));
39         throw std::runtime_error("Failed to open the host console socket");
40     }
41 
42     memset(&addr, 0, sizeof(addr));
43     addr.sun_family = AF_UNIX;
44     memcpy(&addr.sun_path, &CONSOLE_SOCKET_PATH, CONSOLE_SOCKET_PATH_LEN);
45     consoleFD = std::make_unique<CustomFD>(fd);
46     auto& conFD = *(consoleFD.get());
47 
48     rc =
49         connect(conFD(), (struct sockaddr*)&addr,
50                 sizeof(addr) - sizeof(addr.sun_path) + CONSOLE_SOCKET_PATH_LEN);
51     if (rc < 0)
52     {
53         log<level::ERR>("Failed to connect to host console socket address",
54                         entry("ERRNO=%d", errno));
55         consoleFD.reset();
56         throw std::runtime_error("Failed to connect to console server");
57     }
58 }
59 
60 int Manager::writeConsoleSocket(const std::vector<uint8_t>& input) const
61 {
62     auto inBuffer = input.data();
63     auto inBufferSize = input.size();
64     size_t pos = 0;
65     ssize_t rc = 0;
66     int errVal = 0;
67     auto& conFD = *(consoleFD.get());
68 
69     for (pos = 0; pos < inBufferSize; pos += rc)
70     {
71         rc = write(conFD(), inBuffer + pos, inBufferSize - pos);
72         if (rc <= 0)
73         {
74             if (errno == EINTR)
75             {
76                 log<level::INFO>(" Retrying to handle EINTR",
77                                  entry("ERRNO=%d", errno));
78                 rc = 0;
79                 continue;
80             }
81             else
82             {
83                 errVal = errno;
84                 log<level::ERR>("Failed to write to host console socket",
85                                 entry("ERRNO=%d", errno));
86                 return -errVal;
87             }
88         }
89     }
90 
91     return 0;
92 }
93 
94 void Manager::startPayloadInstance(uint8_t payloadInstance,
95                                    session::SessionID sessionID)
96 {
97     if (payloadMap.empty())
98     {
99         initHostConsoleFd();
100 
101         // Register the fd in the sd_event_loop
102         std::get<eventloop::EventLoop&>(singletonPool)
103             .startHostConsole(*(consoleFD.get()));
104     }
105 
106     // Create the SOL Context data for payload instance
107     auto context = std::make_unique<Context>(retryCount, sendThreshold,
108                                              payloadInstance, sessionID);
109 
110     std::get<eventloop::EventLoop&>(singletonPool)
111         .startSOLPayloadInstance(
112             payloadInstance,
113             std::chrono::duration_cast<eventloop::IntervalType>(
114                 accumulateInterval),
115             std::chrono::duration_cast<eventloop::IntervalType>(retryInterval));
116 
117     payloadMap.emplace(payloadInstance, std::move(context));
118 }
119 
120 void Manager::stopPayloadInstance(uint8_t payloadInstance)
121 {
122     auto iter = payloadMap.find(payloadInstance);
123     if (iter == payloadMap.end())
124     {
125         throw std::runtime_error("SOL Payload instance not found ");
126     }
127 
128     payloadMap.erase(iter);
129 
130     std::get<eventloop::EventLoop&>(singletonPool)
131         .stopSOLPayloadInstance(payloadInstance);
132 
133     if (payloadMap.empty())
134     {
135         consoleFD.reset();
136 
137         dataBuffer.erase(dataBuffer.size());
138     }
139 }
140 
141 } // namespace sol
142