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/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..fb28cad
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,40 @@
+sbin_PROGRAMS = \
+	netipmid
+
+netipmid_SOURCES = \
+	endian.hpp \
+	socket_channel.hpp \
+	socket_channel.cpp \
+	message.hpp \
+	auth_algo.hpp \
+	auth_algo.cpp \
+	session.hpp \
+	session.cpp \
+	sessions_manager.hpp \
+	sessions_manager.cpp \
+	message_parsers.hpp \
+	message_parsers.cpp \
+	message_handler.hpp \
+	message_handler.cpp \
+	command_table.hpp \
+	command_table.cpp \
+	command/channel_auth.hpp \
+	command/channel_auth.cpp \
+	command/guid.hpp \
+	command/guid.cpp \
+	command/open_session.hpp \
+	command/open_session.cpp \
+	command/rakp12.hpp \
+	command/rakp12.cpp \
+	command/rakp34.hpp \
+	command/rakp34.cpp \
+	command/session_cmds.hpp \
+	command/session_cmds.cpp \
+	comm_module.hpp \
+	comm_module.cpp \
+	main.hpp \
+	main.cpp \
+
+netipmid_LDFLAGS = $(SYSTEMD_LIBS) $(CRYPTO_LIBS) $(libmapper_LIBS)
+netipmid_CXXFLAGS = $(SYSTEMD_CFLAGS) $(libmapper_CFLAGS)
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..a352eed
--- /dev/null
+++ b/README.md
@@ -0,0 +1,9 @@
+## To Build
+```
+To build this package, do the following steps:
+
+    1. ./bootstrap.sh
+    2. ./configure ${CONFIGURE_FLAGS}
+    3. make
+
+To full clean the repository again run `./bootstrap.sh clean`.
diff --git a/bootstrap.sh b/bootstrap.sh
new file mode 100755
index 0000000..50b75b7
--- /dev/null
+++ b/bootstrap.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+AUTOCONF_FILES="Makefile.in aclocal.m4 ar-lib autom4te.cache compile \
+        config.guess config.h.in config.sub configure depcomp install-sh \
+        ltmain.sh missing *libtool test-driver"
+
+case $1 in
+    clean)
+        test -f Makefile && make maintainer-clean
+        for file in ${AUTOCONF_FILES}; do
+            find -name "$file" | xargs -r rm -rf
+        done
+        exit 0
+        ;;
+esac
+
+autoreconf -i
+echo 'Run "./configure ${CONFIGURE_FLAGS} && make"'
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..1b12c59
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,30 @@
+# Initialization
+AC_PREREQ([2.69])
+AC_INIT([phosphor-net-ipmid], [1.0], [https://github.com/openbmc/phosphor-net-ipmid/issues])
+AC_CONFIG_HEADERS([config.h])
+AM_INIT_AUTOMAKE([subdir-objects -Wall -Werror foreign dist-xz])
+AM_SILENT_RULES([yes])
+
+# Checks for programs.
+AC_PROG_CXX
+AM_PROG_AR
+AC_PROG_INSTALL
+AC_PROG_MAKE_SET
+
+# Surpress the --with-libtool-sysroot error
+LT_INIT
+
+# Checks for typedefs, structures, and compiler characteristics.
+AX_CXX_COMPILE_STDCXX_14([noext])
+AX_APPEND_COMPILE_FLAGS([-Wall -Werror], [CXXFLAGS])
+
+# Checks for libraries.
+PKG_CHECK_MODULES([SYSTEMD], [libsystemd >= 221])
+PKG_CHECK_MODULES([CRYPTO], [libcrypto >= 1.0.2g], ,[AC_MSG_ERROR([can't find openssl libcrypto])])
+AC_CHECK_LIB([mapper], [mapper_get_service], ,[AC_MSG_ERROR([Could not find libmapper...openbmc/phosphor-objmgr package required])])
+
+# Checks for header files.
+AC_CHECK_HEADER(systemd/sd-bus.h, ,[AC_MSG_ERROR([Could not find systemd/sd-bus.h...systemd developement package required])])
+
+AC_CONFIG_FILES([Makefile])
+AC_OUTPUT
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;
+}
diff --git a/socket_channel.cpp b/socket_channel.cpp
index 4a6d827..a29ef8d 100644
--- a/socket_channel.cpp
+++ b/socket_channel.cpp
@@ -15,7 +15,7 @@
 std::string Channel::getRemoteAddress() const
 {
     char tmp[INET_ADDRSTRLEN] = { 0 };
-    inet_ntop(AF_INET, &address.inAddr.sin_addr, tmp, sizeof(tmp));
+    inet_ntop(AF_INET6, &address.inAddr.sin6_addr, tmp, sizeof(tmp));
     return std::string(tmp);
 }
 
diff --git a/socket_channel.hpp b/socket_channel.hpp
index de95bfd..d5f140e 100644
--- a/socket_channel.hpp
+++ b/socket_channel.hpp
@@ -24,7 +24,7 @@
             union
             {
                 sockaddr sockAddr;
-                sockaddr_in inAddr;
+                sockaddr_in6 inAddr;
             };
             size_t addrSize;
         };
@@ -65,7 +65,7 @@
          */
         auto getPort() const
         {
-            return address.inAddr.sin_port;
+            return address.inAddr.sin6_port;
         }
 
         /**