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