blob: d30aafe6b4ac27cac0fdfde64c06c87f44890923 [file] [log] [blame]
Tom Joseph7fd26dd2017-03-14 15:26:26 +05301#include <sys/ioctl.h>
2#include <systemd/sd-daemon.h>
3#include <phosphor-logging/log.hpp>
4#include "main.hpp"
5#include "message_handler.hpp"
6#include "sd_event_loop.hpp"
7
8namespace eventloop
9{
10using namespace phosphor::logging;
11
12static int udp623Handler(sd_event_source* es, int fd, uint32_t revents,
13 void* userdata)
14{
15 std::shared_ptr<udpsocket::Channel> channelPtr;
16 struct timeval timeout;
17 timeout.tv_sec = SELECT_CALL_TIMEOUT;
18 timeout.tv_usec = 0;
19
20 try
21 {
22 channelPtr.reset(new udpsocket::Channel(fd, timeout));
23
24 // Initialize the Message Handler with the socket channel
25 message::Handler msgHandler(channelPtr);
26
27
28 std::unique_ptr<message::Message> inMessage;
29
30 // Read the incoming IPMI packet
31 inMessage = msgHandler.receive();
32 if (inMessage == nullptr)
33 {
34 return 0;
35 }
36
37 // Execute the Command
38 auto outMessage = msgHandler.executeCommand(*(inMessage.get()));
39 if (outMessage == nullptr)
40 {
41 return 0;
42 }
43
44 // Send the response IPMI Message
45 msgHandler.send(*(outMessage.get()));
46 }
47 catch (std::exception& e)
48 {
49 log<level::ERR>("Executing the IPMI message failed");
50 log<level::ERR>(e.what());
51 }
52
53 return 0;
54}
55
Tom Joseph56f24e92017-03-14 16:06:31 +053056static int consoleInputHandler(sd_event_source* es, int fd, uint32_t revents,
57 void* userdata)
58{
59 try
60 {
61 int readSize = 0;
62
63 if (ioctl(fd, FIONREAD, &readSize) < 0)
64 {
65 log<level::ERR>("ioctl failed for FIONREAD:",
66 entry("errno = %d", errno));
67 return 0;
68 }
69
70 std::vector<uint8_t> buffer(readSize);
71 auto bufferSize = buffer.size();
72 ssize_t readDataLen = 0;
73
74 readDataLen = read(fd, buffer.data(), bufferSize);
75
76 // Update the Console buffer with data read from the socket
77 if (readDataLen > 0)
78 {
79 buffer.resize(readDataLen);
80 std::get<sol::Manager&>(singletonPool).dataBuffer.write(buffer);
81 }
82 else if (readDataLen == 0)
83 {
84 log<level::ERR>("Connection Closed for host console socket");
85 }
86 else if (readDataLen < 0) // Error
87 {
88 log<level::ERR>("Reading from host console socket failed:",
89 entry("ERRNO=%d", errno));
90 }
91 }
92 catch (std::exception& e)
93 {
94 log<level::ERR>(e.what());
95 }
96
97 return 0;
98}
99
Tom Joseph7fd26dd2017-03-14 15:26:26 +0530100int EventLoop::startEventLoop()
101{
102 int fd = -1;
103 int r = 0;
104 sigset_t ss;
105 sd_event_source* source = nullptr;
106
107 r = sd_event_default(&event);
108 if (r < 0)
109 {
110 goto finish;
111 }
112
113 if (sigemptyset(&ss) < 0 || sigaddset(&ss, SIGTERM) < 0 ||
114 sigaddset(&ss, SIGINT) < 0)
115 {
116 r = -errno;
117 goto finish;
118 }
119
120 /* Block SIGTERM first, so that the event loop can handle it */
121 if (sigprocmask(SIG_BLOCK, &ss, nullptr) < 0)
122 {
123 r = -errno;
124 goto finish;
125 }
126
127 /* Let's make use of the default handler and "floating" reference features
128 * of sd_event_add_signal() */
129 r = sd_event_add_signal(event, nullptr, SIGTERM, nullptr, nullptr);
130 if (r < 0)
131 {
132 goto finish;
133 }
134
135 r = sd_event_add_signal(event, nullptr, SIGINT, nullptr, nullptr);
136 if (r < 0)
137 {
138 goto finish;
139 }
140
141 if (sd_listen_fds(0) != 1)
142 {
143 log<level::ERR>("No or too many file descriptors received");
144 goto finish;
145 }
146
147 fd = SD_LISTEN_FDS_START;
148
149 r = sd_event_add_io(event, &source, fd, EPOLLIN, udp623Handler, nullptr);
150 if (r < 0)
151 {
152 goto finish;
153 }
154
155 udpIPMI.reset(source);
156 source = nullptr;
157
158 r = sd_event_loop(event);
159
160finish:
161 event = sd_event_unref(event);
162
163 if (fd >= 0)
164 {
165 (void) close(fd);
166 }
167
168 if (r < 0)
169 {
170 log<level::ERR>("Event Loop Failure:",
171 entry("FAILURE=%s", strerror(-r)));
172 }
173
174 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
175}
176
Tom Joseph56f24e92017-03-14 16:06:31 +0530177void EventLoop::startHostConsole(const sol::CustomFD& fd)
178{
179 int rc = 0;
180
181 if((fd() == -1) || hostConsole.get())
182 {
183 throw std::runtime_error("Console descriptor already added");
184 }
185
186 sd_event_source* source = nullptr;
187
188 // Add the fd to the event loop for EPOLLIN
189 rc = sd_event_add_io(
190 event, &source, fd(), EPOLLIN, consoleInputHandler, nullptr);
191 if (rc < 0)
192 {
193 throw std::runtime_error("Failed to add socket descriptor");
194 }
195
196 hostConsole.reset(source);
197 source=nullptr;
198}
199
Tom Josephcfbd43f2017-03-14 16:14:03 +0530200void EventLoop::stopHostConsole()
201{
202 int rc = 0;
203
204 if (hostConsole.get())
205 {
206 // Disable the host console payload
207 rc = sd_event_source_set_enabled(hostConsole.get(), SD_EVENT_OFF);
208 if (rc < 0)
209 {
210 log<level::ERR>("Failed to disable the host console socket",
211 entry("RC=%d", rc));
212 hostConsole.reset();
213 throw std::runtime_error("Failed to disable socket descriptor");
214 }
215
216 hostConsole.reset();
217 }
218}
219
Tom Joseph7fd26dd2017-03-14 15:26:26 +0530220} // namespace eventloop