1 #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 8 namespace eventloop 9 { 10 using namespace phosphor::logging; 11 12 static 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 56 static 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 100 int 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 160 finish: 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 177 void 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 200 void 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 220 void EventLoop::switchTimer(uint8_t payloadInst, 221 Timers type, 222 bool status) 223 { 224 auto iter = payloadInfo.find(payloadInst); 225 if (iter == payloadInfo.end()) 226 { 227 log<level::ERR>("SOL Payload instance not found", 228 entry("payloadInst=%d", payloadInst)); 229 throw std::runtime_error("SOL Payload instance not found"); 230 } 231 232 int rc = 0; 233 auto source = (std::get<0>(iter->second.at(type))).get(); 234 auto interval = std::get<1>(iter->second.at(type)); 235 236 // Turn OFF the timer 237 if (!status) 238 { 239 rc = sd_event_source_set_enabled(source, SD_EVENT_OFF); 240 if (rc < 0) 241 { 242 log<level::ERR>("Failed to disable the timer", entry("RC=%d", rc)); 243 throw std::runtime_error("Failed to disable timer"); 244 } 245 return; 246 } 247 248 // Turn ON the timer 249 uint64_t currentTime = 0; 250 rc = sd_event_now(event, CLOCK_MONOTONIC, ¤tTime); 251 if (rc < 0) 252 { 253 log<level::ERR>("Failed to get the current timestamp", 254 entry("RC=%d", rc)); 255 throw std::runtime_error("Failed to get current timestamp"); 256 } 257 258 rc = sd_event_source_set_time(source, currentTime + interval.count()); 259 if (rc < 0) 260 { 261 log<level::ERR>("sd_event_source_set_time function failed", 262 entry("RC=%d", rc)); 263 throw std::runtime_error("sd_event_source_set_time function failed"); 264 } 265 266 rc = sd_event_source_set_enabled(source, SD_EVENT_ONESHOT); 267 if (rc < 0) 268 { 269 log<level::ERR>("Failed to enable the timer", entry("RC=%d",rc)); 270 throw std::runtime_error("Failed to enable timer"); 271 } 272 } 273 274 } // namespace eventloop 275