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