IPMI Main Handler

This patch contains the entry point for the IPMI RMCP Server. It
registers the session setup commands and start the IPMI event
handler.

Resolves openbmc/openbmc#429

Change-Id: I98a615eef9becb29964f8ec93e59d061bfcdfac3
Signed-off-by: Tom Joseph <tomjoseph@in.ibm.com>
diff --git a/main.cpp b/main.cpp
new file mode 100644
index 0000000..0fae8a7
--- /dev/null
+++ b/main.cpp
@@ -0,0 +1,193 @@
+#include "main.hpp"
+#include <assert.h>
+#include <dlfcn.h>
+#include <dirent.h>
+#include <unistd.h>
+
+#include <iostream>
+#include <tuple>
+
+#include <systemd/sd-bus.h>
+#include <systemd/sd-daemon.h>
+#include <systemd/sd-event.h>
+
+#include <host-ipmid/ipmid-api.h>
+#include "comm_module.hpp"
+#include "command_table.hpp"
+#include "message.hpp"
+#include "message_handler.hpp"
+#include "sessions_manager.hpp"
+#include "socket_channel.hpp"
+
+// Tuple of Global Singletons
+session::Manager manager;
+command::Table table;
+std::tuple<session::Manager&, command::Table&> singletonPool(manager, table);
+
+sd_bus* bus = nullptr;
+
+/*
+ * @brief Required by apphandler IPMI Provider Library
+ */
+sd_bus* ipmid_get_sd_bus_connection()
+{
+    return bus;
+}
+
+/*
+ * TODO : The plan is to refactor the event loop to support adding multiple
+ * file descriptors and event handlers for implementing the Serial Over LAN.
+ *
+ * A class would abstract the features provided by the sd_event_loop
+ */
+
+namespace eventloop
+{
+
+static int io_handler(sd_event_source* es, int fd, uint32_t revents,
+                      void* userdata)
+{
+    std::shared_ptr<udpsocket::Channel> channelPtr;
+    struct timeval timeout;
+    timeout.tv_sec = SELECT_CALL_TIMEOUT;
+    timeout.tv_usec = 0;
+
+    channelPtr.reset(new udpsocket::Channel(fd, timeout));
+
+    // Initialize the Message Handler with the socket channel
+    message::Handler msgHandler(channelPtr);
+
+    // Read the incoming IPMI packet
+    std::unique_ptr<message::Message> inMessage;
+    try
+    {
+        inMessage = msgHandler.receive();
+    }
+    catch (std::exception& e)
+    {
+        std::cerr << "Reading & Parsing the incoming IPMI message failed\n";
+        std::cerr << e.what() << "\n";
+        return 0;
+    }
+
+    // Execute the Command
+    auto outMessage = msgHandler.executeCommand(*inMessage.get());
+    if (outMessage == nullptr)
+    {
+        std::cerr << "Execution of IPMI command failed\n";
+        return 0;
+    }
+
+    // Send the response IPMI Message
+    msgHandler.send(*outMessage.get());
+
+    return 0;
+}
+
+int startEventLoop()
+{
+    struct sockaddr_in6 in {};
+
+    sd_event_source* event_source = nullptr;
+    sd_event* event = nullptr;
+    int fd = -1, r;
+    sigset_t ss;
+
+    r = sd_event_default(&event);
+    if (r < 0)
+    {
+        goto finish;
+    }
+
+    if (sigemptyset(&ss) < 0 || sigaddset(&ss, SIGTERM) < 0 ||
+        sigaddset(&ss, SIGINT) < 0)
+    {
+        r = -errno;
+        goto finish;
+    }
+
+    /* Block SIGTERM first, so that the event loop can handle it */
+    if (sigprocmask(SIG_BLOCK, &ss, nullptr) < 0)
+    {
+        r = -errno;
+        goto finish;
+    }
+
+    /* Let's make use of the default handler and "floating" reference features
+     * of sd_event_add_signal() */
+    r = sd_event_add_signal(event, nullptr, SIGTERM, nullptr, nullptr);
+    if (r < 0)
+    {
+        goto finish;
+    }
+
+    r = sd_event_add_signal(event, nullptr, SIGINT, nullptr, nullptr);
+    if (r < 0)
+    {
+        goto finish;
+    }
+
+    fd = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
+    if (fd < 0)
+    {
+        r = -errno;
+        goto finish;
+    }
+
+    in.sin6_family = AF_INET6;
+    in.sin6_port = htons(IPMI_STD_PORT);
+
+    if (bind(fd, (struct sockaddr*)&in, sizeof(in)) < 0)
+    {
+        r = -errno;
+        goto finish;
+    }
+
+    r = sd_event_add_io(event, &event_source, fd, EPOLLIN, io_handler, nullptr);
+    if (r < 0)
+    {
+        goto finish;
+    }
+
+    r = sd_event_loop(event);
+
+finish:
+    event_source = sd_event_source_unref(event_source);
+    event = sd_event_unref(event);
+
+    if (fd >= 0)
+    {
+        (void) close(fd);
+    }
+
+    if (r < 0)
+    {
+        fprintf(stderr, "Failure: %s\n", strerror(-r));
+    }
+
+    return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+}
+
+} // namespace eventloop
+
+int main(int i_argc, char* i_argv[])
+{
+    // Connect to system bus
+    auto rc = sd_bus_open_system(&bus);
+    if (rc < 0)
+    {
+        std::cerr << "Failed to connect to system bus:" << strerror(-rc) <<"\n";
+        goto finish;
+    }
+
+    // Register the phosphor-net-ipmid session setup commands
+    command::sessionSetupCommands();
+
+    // Start Event Loop
+    return eventloop::startEventLoop();
+
+finish:
+    sd_bus_unref(bus);
+
+    return 0;
+}