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