blob: 108cf9203166c838a649165bbd71e3d30fead5b8 [file] [log] [blame]
Tom Josephc35524e2016-08-29 08:17:59 -05001#include "main.hpp"
2#include <assert.h>
3#include <dlfcn.h>
4#include <dirent.h>
5#include <unistd.h>
6
7#include <iostream>
8#include <tuple>
9
10#include <systemd/sd-bus.h>
11#include <systemd/sd-daemon.h>
12#include <systemd/sd-event.h>
13
14#include <host-ipmid/ipmid-api.h>
15#include "comm_module.hpp"
16#include "command_table.hpp"
17#include "message.hpp"
18#include "message_handler.hpp"
Tom485038e2016-12-02 13:44:45 +053019#include "provider_registration.hpp"
Tom Josephc35524e2016-08-29 08:17:59 -050020#include "sessions_manager.hpp"
21#include "socket_channel.hpp"
22
23// Tuple of Global Singletons
24session::Manager manager;
25command::Table table;
26std::tuple<session::Manager&, command::Table&> singletonPool(manager, table);
27
28sd_bus* bus = nullptr;
29
30/*
31 * @brief Required by apphandler IPMI Provider Library
32 */
33sd_bus* ipmid_get_sd_bus_connection()
34{
35 return bus;
36}
37
38/*
39 * TODO : The plan is to refactor the event loop to support adding multiple
40 * file descriptors and event handlers for implementing the Serial Over LAN.
41 *
42 * A class would abstract the features provided by the sd_event_loop
43 */
44
45namespace eventloop
46{
47
48static int io_handler(sd_event_source* es, int fd, uint32_t revents,
49 void* userdata)
50{
51 std::shared_ptr<udpsocket::Channel> channelPtr;
52 struct timeval timeout;
53 timeout.tv_sec = SELECT_CALL_TIMEOUT;
54 timeout.tv_usec = 0;
55
56 channelPtr.reset(new udpsocket::Channel(fd, timeout));
57
58 // Initialize the Message Handler with the socket channel
59 message::Handler msgHandler(channelPtr);
60
61 // Read the incoming IPMI packet
62 std::unique_ptr<message::Message> inMessage;
63 try
64 {
65 inMessage = msgHandler.receive();
66 }
67 catch (std::exception& e)
68 {
69 std::cerr << "Reading & Parsing the incoming IPMI message failed\n";
70 std::cerr << e.what() << "\n";
71 return 0;
72 }
73
74 // Execute the Command
75 auto outMessage = msgHandler.executeCommand(*inMessage.get());
76 if (outMessage == nullptr)
77 {
78 std::cerr << "Execution of IPMI command failed\n";
79 return 0;
80 }
81
82 // Send the response IPMI Message
83 msgHandler.send(*outMessage.get());
84
85 return 0;
86}
87
88int startEventLoop()
89{
90 struct sockaddr_in6 in {};
91
92 sd_event_source* event_source = nullptr;
93 sd_event* event = nullptr;
94 int fd = -1, r;
95 sigset_t ss;
96
97 r = sd_event_default(&event);
98 if (r < 0)
99 {
100 goto finish;
101 }
102
103 if (sigemptyset(&ss) < 0 || sigaddset(&ss, SIGTERM) < 0 ||
104 sigaddset(&ss, SIGINT) < 0)
105 {
106 r = -errno;
107 goto finish;
108 }
109
110 /* Block SIGTERM first, so that the event loop can handle it */
111 if (sigprocmask(SIG_BLOCK, &ss, nullptr) < 0)
112 {
113 r = -errno;
114 goto finish;
115 }
116
117 /* Let's make use of the default handler and "floating" reference features
118 * of sd_event_add_signal() */
119 r = sd_event_add_signal(event, nullptr, SIGTERM, nullptr, nullptr);
120 if (r < 0)
121 {
122 goto finish;
123 }
124
125 r = sd_event_add_signal(event, nullptr, SIGINT, nullptr, nullptr);
126 if (r < 0)
127 {
128 goto finish;
129 }
130
131 fd = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
132 if (fd < 0)
133 {
134 r = -errno;
135 goto finish;
136 }
137
138 in.sin6_family = AF_INET6;
139 in.sin6_port = htons(IPMI_STD_PORT);
140
141 if (bind(fd, (struct sockaddr*)&in, sizeof(in)) < 0)
142 {
143 r = -errno;
144 goto finish;
145 }
146
147 r = sd_event_add_io(event, &event_source, fd, EPOLLIN, io_handler, nullptr);
148 if (r < 0)
149 {
150 goto finish;
151 }
152
153 r = sd_event_loop(event);
154
155finish:
156 event_source = sd_event_source_unref(event_source);
157 event = sd_event_unref(event);
158
159 if (fd >= 0)
160 {
161 (void) close(fd);
162 }
163
164 if (r < 0)
165 {
166 fprintf(stderr, "Failure: %s\n", strerror(-r));
167 }
168
169 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
170}
171
172} // namespace eventloop
173
174int main(int i_argc, char* i_argv[])
175{
176 // Connect to system bus
177 auto rc = sd_bus_open_system(&bus);
178 if (rc < 0)
179 {
180 std::cerr << "Failed to connect to system bus:" << strerror(-rc) <<"\n";
181 goto finish;
182 }
183
Tom485038e2016-12-02 13:44:45 +0530184 // Register all the IPMI provider libraries applicable for net-ipmid
185 provider::registerCallbackHandlers(NET_IPMID_LIB_PATH);
186
Tom Josephc35524e2016-08-29 08:17:59 -0500187 // Register the phosphor-net-ipmid session setup commands
188 command::sessionSetupCommands();
189
190 // Start Event Loop
191 return eventloop::startEventLoop();
192
193finish:
194 sd_bus_unref(bus);
195
196 return 0;
197}