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 int EventLoop::startEventLoop()
57 {
58     int fd = -1;
59     int r = 0;
60     sigset_t ss;
61     sd_event_source* source = nullptr;
62 
63     r = sd_event_default(&event);
64     if (r < 0)
65     {
66         goto finish;
67     }
68 
69     if (sigemptyset(&ss) < 0 || sigaddset(&ss, SIGTERM) < 0 ||
70         sigaddset(&ss, SIGINT) < 0)
71     {
72         r = -errno;
73         goto finish;
74     }
75 
76     /* Block SIGTERM first, so that the event loop can handle it */
77     if (sigprocmask(SIG_BLOCK, &ss, nullptr) < 0)
78     {
79         r = -errno;
80         goto finish;
81     }
82 
83     /* Let's make use of the default handler and "floating" reference features
84      * of sd_event_add_signal() */
85     r = sd_event_add_signal(event, nullptr, SIGTERM, nullptr, nullptr);
86     if (r < 0)
87     {
88         goto finish;
89     }
90 
91     r = sd_event_add_signal(event, nullptr, SIGINT, nullptr, nullptr);
92     if (r < 0)
93     {
94         goto finish;
95     }
96 
97     if (sd_listen_fds(0) != 1)
98     {
99         log<level::ERR>("No or too many file descriptors received");
100         goto finish;
101     }
102 
103     fd = SD_LISTEN_FDS_START;
104 
105     r = sd_event_add_io(event, &source, fd, EPOLLIN, udp623Handler, nullptr);
106     if (r < 0)
107     {
108         goto finish;
109     }
110 
111     udpIPMI.reset(source);
112     source = nullptr;
113 
114     r = sd_event_loop(event);
115 
116 finish:
117     event = sd_event_unref(event);
118 
119     if (fd >= 0)
120     {
121         (void) close(fd);
122     }
123 
124     if (r < 0)
125     {
126         log<level::ERR>("Event Loop Failure:",
127                 entry("FAILURE=%s", strerror(-r)));
128     }
129 
130     return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
131 }
132 
133 } // namespace eventloop
134