blob: 27b27c9e5101c39b2ff56dfd4e3f465d61131f70 [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
93 // Send the response IPMI Message
Tom069f01e2016-12-02 14:11:37 +053094 msgHandler.send(*(outMessage.get()));
Tom Josephc35524e2016-08-29 08:17:59 -050095
96 return 0;
97}
98
99int startEventLoop()
100{
101 struct sockaddr_in6 in {};
102
103 sd_event_source* event_source = nullptr;
104 sd_event* event = nullptr;
105 int fd = -1, r;
106 sigset_t ss;
107
108 r = sd_event_default(&event);
109 if (r < 0)
110 {
111 goto finish;
112 }
113
114 if (sigemptyset(&ss) < 0 || sigaddset(&ss, SIGTERM) < 0 ||
115 sigaddset(&ss, SIGINT) < 0)
116 {
117 r = -errno;
118 goto finish;
119 }
120
121 /* Block SIGTERM first, so that the event loop can handle it */
122 if (sigprocmask(SIG_BLOCK, &ss, nullptr) < 0)
123 {
124 r = -errno;
125 goto finish;
126 }
127
128 /* Let's make use of the default handler and "floating" reference features
129 * of sd_event_add_signal() */
130 r = sd_event_add_signal(event, nullptr, SIGTERM, nullptr, nullptr);
131 if (r < 0)
132 {
133 goto finish;
134 }
135
136 r = sd_event_add_signal(event, nullptr, SIGINT, nullptr, nullptr);
137 if (r < 0)
138 {
139 goto finish;
140 }
141
142 fd = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
143 if (fd < 0)
144 {
145 r = -errno;
146 goto finish;
147 }
148
149 in.sin6_family = AF_INET6;
150 in.sin6_port = htons(IPMI_STD_PORT);
151
152 if (bind(fd, (struct sockaddr*)&in, sizeof(in)) < 0)
153 {
154 r = -errno;
155 goto finish;
156 }
157
158 r = sd_event_add_io(event, &event_source, fd, EPOLLIN, io_handler, nullptr);
159 if (r < 0)
160 {
161 goto finish;
162 }
163
164 r = sd_event_loop(event);
165
166finish:
167 event_source = sd_event_source_unref(event_source);
168 event = sd_event_unref(event);
169
170 if (fd >= 0)
171 {
172 (void) close(fd);
173 }
174
175 if (r < 0)
176 {
177 fprintf(stderr, "Failure: %s\n", strerror(-r));
178 }
179
180 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
181}
182
183} // namespace eventloop
184
185int main(int i_argc, char* i_argv[])
186{
Tom069f01e2016-12-02 14:11:37 +0530187
188 /*
189 * Required by apphandler IPMI Provider Library for logging.
190 */
191 ipmidbus = fopen("/dev/null", "w");
192
Tom Josephc35524e2016-08-29 08:17:59 -0500193 // Connect to system bus
194 auto rc = sd_bus_open_system(&bus);
195 if (rc < 0)
196 {
197 std::cerr << "Failed to connect to system bus:" << strerror(-rc) <<"\n";
198 goto finish;
199 }
200
Tom485038e2016-12-02 13:44:45 +0530201 // Register all the IPMI provider libraries applicable for net-ipmid
202 provider::registerCallbackHandlers(NET_IPMID_LIB_PATH);
203
Tom Josephc35524e2016-08-29 08:17:59 -0500204 // Register the phosphor-net-ipmid session setup commands
205 command::sessionSetupCommands();
206
207 // Start Event Loop
208 return eventloop::startEventLoop();
209
210finish:
211 sd_bus_unref(bus);
212
213 return 0;
214}