kcsbridge: Daemon rewrite

This focuses on improving compile time, output size, and correctness
of command handling. Notably, it adds the ability for the host to cancel
outstanding IPMI calls when the host decides they should time out. It
ensures that canceled calls do not end up writing over the response for
an incoming request. Since the host can now cancel calls, we remove
internal DBus timeouts and instead require the host to drive any timeout
logic it desires for communications. This gives the host more control
and better adheres to the wishes of the specification.

Change-Id: I526169253931b9bcc4910afa0b54b304d4a9bef3
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644
index 0000000..e8863e8
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,85 @@
+#include "args.hpp"
+#include "cmd.hpp"
+#include "server.hpp"
+
+#include <fmt/format.h>
+#include <systemd/sd-daemon.h>
+
+#include <sdbusplus/bus.hpp>
+#include <sdbusplus/slot.hpp>
+#include <sdeventplus/event.hpp>
+#include <sdeventplus/source/io.hpp>
+#include <sdeventplus/source/signal.hpp>
+#include <stdplus/exception.hpp>
+#include <stdplus/fd/create.hpp>
+#include <stdplus/signal.hpp>
+
+#include <algorithm>
+#include <stdexcept>
+#include <string>
+
+namespace kcsbridge
+{
+
+using sdeventplus::source::IO;
+using sdeventplus::source::Signal;
+using stdplus::fd::OpenAccess;
+using stdplus::fd::OpenFlag;
+using stdplus::fd::OpenFlags;
+
+int execute(const char* channel)
+{
+    // Set up our DBus and event loop
+    auto event = sdeventplus::Event::get_default();
+    auto bus = sdbusplus::bus::new_default();
+    bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
+
+    // Configure basic signal handling
+    auto exit_handler = [&event](Signal&, const struct signalfd_siginfo*) {
+        fmt::print(stderr, "Interrupted, Exiting\n");
+        event.exit(0);
+    };
+    stdplus::signal::block(SIGINT);
+    Signal sig_int(event, SIGINT, exit_handler);
+    stdplus::signal::block(SIGTERM);
+    Signal sig_term(event, SIGTERM, exit_handler);
+
+    // Open an FD for the KCS channel
+    stdplus::ManagedFd kcs = stdplus::fd::open(
+        fmt::format("/dev/{}", channel),
+        OpenFlags(OpenAccess::ReadWrite).set(OpenFlag::NonBlock));
+    sdbusplus::slot::slot slot(nullptr);
+
+    // Add a reader to the bus for handling inbound IPMI
+    IO ioSource(
+        event, kcs.get(), EPOLLIN | EPOLLET,
+        stdplus::exception::ignore(
+            [&kcs, &bus, &slot](IO&, int, uint32_t) { read(kcs, bus, slot); }));
+
+    // Allow processes to affect the state machine
+    std::string dbusChannel = channel;
+    std::replace(dbusChannel.begin(), dbusChannel.end(), '-', '_');
+    auto obj = "/xyz/openbmc_project/Ipmi/Channel/" + dbusChannel;
+    auto srv = "xyz.openbmc_project.Ipmi.Channel." + dbusChannel;
+    auto intf = createSMSHandler(bus, obj.c_str(), kcs);
+    bus.request_name(srv.c_str());
+
+    sd_notify(0, "READY=1");
+    return event.loop();
+}
+
+} // namespace kcsbridge
+
+int main(int argc, char* argv[])
+{
+    try
+    {
+        kcsbridge::Args args(argc, argv);
+        return kcsbridge::execute(args.channel);
+    }
+    catch (const std::exception& e)
+    {
+        fmt::print(stderr, "FAILED: {}\n", e.what());
+        return 1;
+    }
+}