bugfix: load handlers and use factory symbol

Use a predefined factory symbol to build each handler after loading the
library.

Change-Id: I0369c6e46a57c2e8533409d8b06eb74a3962434c
Signed-off-by: Patrick Venture <venture@google.com>
diff --git a/configure.ac b/configure.ac
index efdd0b8..db3bc83 100644
--- a/configure.ac
+++ b/configure.ac
@@ -17,7 +17,7 @@
 AX_APPEND_COMPILE_FLAGS([-Wall -Werror], [CXXFLAGS])
 
 # Checks for library functions.
-LT_INIT([dlopen]) # Required for systemd linking
+LT_INIT([dlopen disable-static shared]) # Required for systemd linking
 LT_LIB_DLLOAD
 
 # Checks for libraries.
diff --git a/example/example.cpp b/example/example.cpp
index 929e4d1..cc36e88 100644
--- a/example/example.cpp
+++ b/example/example.cpp
@@ -181,11 +181,17 @@
 
 void setupExampleHandler()
 {
-    auto* manager = getBlobManager();
-    if (!manager->registerHandler(std::make_unique<ExampleBlobHandler>()))
-    {
-        log<level::ERR>("Failed to register Example Handler");
-    }
+    // You don't need to do anything in the constructor.
 }
 
 } // namespace blobs
+
+/**
+ * This method is required by the blob manager.
+ *
+ * It is called to grab a handler for registering the blob handler instance.
+ */
+std::unique_ptr<blobs::GenericBlobInterface> createHandler()
+{
+    return std::make_unique<blobs::ExampleBlobHandler>();
+}
diff --git a/example/example.hpp b/example/example.hpp
index a85c275..335eade 100644
--- a/example/example.hpp
+++ b/example/example.hpp
@@ -1,10 +1,25 @@
 #pragma once
 
 #include <blobs-ipmid/blobs.hpp>
+#include <memory>
 #include <string>
 #include <unordered_map>
 #include <vector>
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * This method must be declared as extern C for blob manager to lookup the
+ * symbol.
+ */
+std::unique_ptr<blobs::GenericBlobInterface> createHandler();
+
+#ifdef __cplusplus
+}
+#endif
+
 namespace blobs
 {
 
diff --git a/utils.cpp b/utils.cpp
index 5253c1c..2395a2e 100644
--- a/utils.cpp
+++ b/utils.cpp
@@ -2,7 +2,9 @@
 
 #include <dlfcn.h>
 
+#include <blobs-ipmid/manager.hpp>
 #include <experimental/filesystem>
+#include <memory>
 #include <phosphor-logging/log.hpp>
 #include <regex>
 
@@ -12,9 +14,13 @@
 namespace fs = std::experimental::filesystem;
 using namespace phosphor::logging;
 
+using HandlerFactory = std::unique_ptr<GenericBlobInterface> (*)();
+
 void loadLibraries(const std::string& path)
 {
     void* libHandle = NULL;
+    HandlerFactory factory;
+    auto* manager = getBlobManager();
 
     for (const auto& p : fs::recursive_directory_iterator(path))
     {
@@ -30,12 +36,37 @@
             continue;
         }
 
-        libHandle = dlopen(ps.c_str(), RTLD_NOW);
+        libHandle = dlopen(ps.c_str(), RTLD_NOW | RTLD_GLOBAL);
         if (!libHandle)
         {
             log<level::ERR>("ERROR opening", entry("HANDLER=%s", ps.c_str()),
                             entry("ERROR=%s", dlerror()));
+            continue;
         }
+
+        dlerror(); /* Clear any previous error. */
+
+        factory =
+            reinterpret_cast<HandlerFactory>(dlsym(libHandle, "createHandler"));
+
+        const char* error = dlerror();
+        if (error)
+        {
+            log<level::ERR>("ERROR loading symbol",
+                            entry("HANDLER=%s", ps.c_str()),
+                            entry("ERROR=%s", error));
+            continue;
+        }
+
+        std::unique_ptr<GenericBlobInterface> result = factory();
+        if (!result)
+        {
+            log<level::ERR>("Unable to create handler",
+                            entry("HANDLER=%s", ps.c_str()));
+            continue;
+        }
+
+        manager->registerHandler(std::move(result));
     }
 }