blob: f6cdeec119ce4b23df0a9367167b2d8c262c58b8 [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 "socket_channel.hpp"
21
22// Tuple of Global Singletons
23session::Manager manager;
24command::Table table;
Tom Joseph52f53d72017-03-14 15:20:19 +053025eventloop::EventLoop loop;
26sol::Manager solManager;
27
28std::tuple<session::Manager&, command::Table&, eventloop::EventLoop&,
29 sol::Manager&> singletonPool(manager, table, loop, solManager);
Tom Josephc35524e2016-08-29 08:17:59 -050030
31sd_bus* bus = nullptr;
Tom069f01e2016-12-02 14:11:37 +053032FILE* ipmidbus = nullptr;
33unsigned short g_sel_reserve = 0xFFFF;
34sd_bus_slot* ipmid_slot = nullptr;
Tom Josephc35524e2016-08-29 08:17:59 -050035
36/*
37 * @brief Required by apphandler IPMI Provider Library
38 */
39sd_bus* ipmid_get_sd_bus_connection()
40{
41 return bus;
42}
43
44/*
Tom069f01e2016-12-02 14:11:37 +053045 * @brief Required by apphandler IPMI Provider Library
46 */
47unsigned short get_sel_reserve_id()
48{
49 return g_sel_reserve;
50}
51
52/*
Tom Josephc35524e2016-08-29 08:17:59 -050053 * TODO : The plan is to refactor the event loop to support adding multiple
54 * file descriptors and event handlers for implementing the Serial Over LAN.
55 *
56 * A class would abstract the features provided by the sd_event_loop
57 */
58
59namespace eventloop
60{
61
62static int io_handler(sd_event_source* es, int fd, uint32_t revents,
63 void* userdata)
64{
65 std::shared_ptr<udpsocket::Channel> channelPtr;
66 struct timeval timeout;
67 timeout.tv_sec = SELECT_CALL_TIMEOUT;
68 timeout.tv_usec = 0;
69
70 channelPtr.reset(new udpsocket::Channel(fd, timeout));
71
72 // Initialize the Message Handler with the socket channel
73 message::Handler msgHandler(channelPtr);
74
75 // Read the incoming IPMI packet
76 std::unique_ptr<message::Message> inMessage;
77 try
78 {
79 inMessage = msgHandler.receive();
80 }
81 catch (std::exception& e)
82 {
83 std::cerr << "Reading & Parsing the incoming IPMI message failed\n";
84 std::cerr << e.what() << "\n";
85 return 0;
86 }
87
88 // Execute the Command
Tom069f01e2016-12-02 14:11:37 +053089 auto outMessage = msgHandler.executeCommand(*(inMessage.get()));
Tom Josephc35524e2016-08-29 08:17:59 -050090 if (outMessage == nullptr)
91 {
92 std::cerr << "Execution of IPMI command failed\n";
93 return 0;
94 }
95
Tom Joseph73a3d962017-01-24 16:45:28 +053096 try
97 {
98 // Send the response IPMI Message
99 msgHandler.send(*(outMessage.get()));
100 }
101 catch (std::exception& e)
102 {
103 std::cerr << "Flattening & Sending the outgoing IPMI message failed\n";
104 std::cerr << e.what() << "\n";
105 }
Tom Josephc35524e2016-08-29 08:17:59 -0500106
107 return 0;
108}
109
110int startEventLoop()
111{
Tom Josephc35524e2016-08-29 08:17:59 -0500112 sd_event_source* event_source = nullptr;
113 sd_event* event = nullptr;
114 int fd = -1, r;
115 sigset_t ss;
116
117 r = sd_event_default(&event);
118 if (r < 0)
119 {
120 goto finish;
121 }
122
123 if (sigemptyset(&ss) < 0 || sigaddset(&ss, SIGTERM) < 0 ||
124 sigaddset(&ss, SIGINT) < 0)
125 {
126 r = -errno;
127 goto finish;
128 }
129
130 /* Block SIGTERM first, so that the event loop can handle it */
131 if (sigprocmask(SIG_BLOCK, &ss, nullptr) < 0)
132 {
133 r = -errno;
134 goto finish;
135 }
136
137 /* Let's make use of the default handler and "floating" reference features
138 * of sd_event_add_signal() */
139 r = sd_event_add_signal(event, nullptr, SIGTERM, nullptr, nullptr);
140 if (r < 0)
141 {
142 goto finish;
143 }
144
145 r = sd_event_add_signal(event, nullptr, SIGINT, nullptr, nullptr);
146 if (r < 0)
147 {
148 goto finish;
149 }
150
Tom Joseph76931bf2017-01-27 08:40:42 +0530151 if (sd_listen_fds(0) != 1)
Tom Josephc35524e2016-08-29 08:17:59 -0500152 {
Tom Joseph76931bf2017-01-27 08:40:42 +0530153 fprintf(stderr, "No or too many file descriptors received.\n");
Tom Josephc35524e2016-08-29 08:17:59 -0500154 goto finish;
155 }
156
Tom Joseph76931bf2017-01-27 08:40:42 +0530157 fd = SD_LISTEN_FDS_START;
Tom Josephc35524e2016-08-29 08:17:59 -0500158
159 r = sd_event_add_io(event, &event_source, fd, EPOLLIN, io_handler, nullptr);
160 if (r < 0)
161 {
162 goto finish;
163 }
164
165 r = sd_event_loop(event);
166
167finish:
168 event_source = sd_event_source_unref(event_source);
169 event = sd_event_unref(event);
170
171 if (fd >= 0)
172 {
173 (void) close(fd);
174 }
175
176 if (r < 0)
177 {
178 fprintf(stderr, "Failure: %s\n", strerror(-r));
179 }
180
181 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
182}
183
184} // namespace eventloop
185
186int main(int i_argc, char* i_argv[])
187{
Tom069f01e2016-12-02 14:11:37 +0530188
189 /*
190 * Required by apphandler IPMI Provider Library for logging.
191 */
192 ipmidbus = fopen("/dev/null", "w");
193
Tom Josephc35524e2016-08-29 08:17:59 -0500194 // Connect to system bus
195 auto rc = sd_bus_open_system(&bus);
196 if (rc < 0)
197 {
198 std::cerr << "Failed to connect to system bus:" << strerror(-rc) <<"\n";
199 goto finish;
200 }
201
Tom485038e2016-12-02 13:44:45 +0530202 // Register all the IPMI provider libraries applicable for net-ipmid
203 provider::registerCallbackHandlers(NET_IPMID_LIB_PATH);
204
Tom Josephc35524e2016-08-29 08:17:59 -0500205 // Register the phosphor-net-ipmid session setup commands
206 command::sessionSetupCommands();
207
208 // Start Event Loop
209 return eventloop::startEventLoop();
210
211finish:
212 sd_bus_unref(bus);
213
214 return 0;
215}