| Tom Joseph | c35524e | 2016-08-29 08:17:59 -0500 | [diff] [blame] | 1 | #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" | 
| Tom | 485038e | 2016-12-02 13:44:45 +0530 | [diff] [blame^] | 19 | #include "provider_registration.hpp" | 
| Tom Joseph | c35524e | 2016-08-29 08:17:59 -0500 | [diff] [blame] | 20 | #include "sessions_manager.hpp" | 
|  | 21 | #include "socket_channel.hpp" | 
|  | 22 |  | 
|  | 23 | // Tuple of Global Singletons | 
|  | 24 | session::Manager manager; | 
|  | 25 | command::Table table; | 
|  | 26 | std::tuple<session::Manager&, command::Table&> singletonPool(manager, table); | 
|  | 27 |  | 
|  | 28 | sd_bus* bus = nullptr; | 
|  | 29 |  | 
|  | 30 | /* | 
|  | 31 | * @brief Required by apphandler IPMI Provider Library | 
|  | 32 | */ | 
|  | 33 | sd_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 |  | 
|  | 45 | namespace eventloop | 
|  | 46 | { | 
|  | 47 |  | 
|  | 48 | static 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 |  | 
|  | 88 | int 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 |  | 
|  | 155 | finish: | 
|  | 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 |  | 
|  | 174 | int 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 |  | 
| Tom | 485038e | 2016-12-02 13:44:45 +0530 | [diff] [blame^] | 184 | // Register all the IPMI provider libraries applicable for net-ipmid | 
|  | 185 | provider::registerCallbackHandlers(NET_IPMID_LIB_PATH); | 
|  | 186 |  | 
| Tom Joseph | c35524e | 2016-08-29 08:17:59 -0500 | [diff] [blame] | 187 | // Register the phosphor-net-ipmid session setup commands | 
|  | 188 | command::sessionSetupCommands(); | 
|  | 189 |  | 
|  | 190 | // Start Event Loop | 
|  | 191 | return eventloop::startEventLoop(); | 
|  | 192 |  | 
|  | 193 | finish: | 
|  | 194 | sd_bus_unref(bus); | 
|  | 195 |  | 
|  | 196 | return 0; | 
|  | 197 | } |