Add better error handling for findDbusObjects

The mapper seems to not respond occasionally, become
less reliant on it.

Change-Id: I957cadaf107de3659698804b74d5214ce6606f6c
Signed-off-by: James Feist <james.feist@linux.intel.com>
diff --git a/src/EntityManager.cpp b/src/EntityManager.cpp
index 7b91159..c9d0c15 100644
--- a/src/EntityManager.cpp
+++ b/src/EntityManager.cpp
@@ -100,6 +100,10 @@
         &interfaceDevices,
     std::string interface)
 {
+    // todo: this is only static because the mapper is unreliable as of today
+    static boost::container::flat_map<std::string,
+                                      boost::container::flat_set<std::string>>
+        connections;
     // find all connections in the mapper that expose a specific type
     static const dbus::endpoint mapper("xyz.openbmc_project.ObjectMapper",
                                        "/xyz/openbmc_project/object_mapper",
@@ -112,32 +116,60 @@
         std::cerr << "Pack Failed GetSensorSubtree\n";
         return false;
     }
-    dbus::message getMapResp = connection->send(getMap);
+
     GetSubTreeType interfaceSubtree;
-    if (!getMapResp.unpack(interfaceSubtree))
+    size_t retries = 1;
+    bool unpackStatus = false;
+    // the mapper seems to hang occasionally, not responding, so we give it a
+    // timeout and retries
+    do
     {
-        std::cerr << "Error communicating to mapper\n";
-        return false;
-    }
-    boost::container::flat_set<std::string> connections;
-    for (auto &object : interfaceSubtree)
+        dbus::message getMapResp =
+            connection->send(getMap, std::chrono::seconds(2));
+        unpackStatus = getMapResp.unpack(interfaceSubtree);
+
+    } while (retries-- && !unpackStatus);
+
+    auto &interfaceConnections = connections[interface];
+    if (!unpackStatus)
     {
-        for (auto &connPair : object.second)
+        std::cerr << "Error communicating to mapper, using cached data if "
+                     "available\n";
+        if (interfaceConnections.empty())
         {
-            connections.insert(connPair.first);
+            return false;
+        }
+    }
+
+    if (unpackStatus)
+    {
+        interfaceConnections.clear();
+        for (auto &object : interfaceSubtree)
+        {
+            for (auto &connPair : object.second)
+            {
+                interfaceConnections.insert(connPair.first);
+            }
         }
     }
     // iterate through the connections, adding creating individual device
     // dictionaries
-    for (auto &conn : connections)
+    for (auto &conn : interfaceConnections)
     {
         auto managedObj =
             dbus::endpoint(conn, "/", "org.freedesktop.DBus.ObjectManager",
                            "GetManagedObjects");
         dbus::message getManagedObj = dbus::message::new_call(managedObj);
-        dbus::message getManagedObjResp = connection->send(getManagedObj);
         ManagedObjectType managedInterface;
-        if (!getManagedObjResp.unpack(managedInterface))
+        retries = 1;
+        unpackStatus = false;
+        do
+        {
+            dbus::message getManagedObjResp = connection->send(getManagedObj);
+            unpackStatus = getManagedObjResp.unpack(managedInterface);
+        } while (retries-- && !unpackStatus);
+
+        if (!unpackStatus)
         {
             std::cerr << "error getting managed object for device " << conn
                       << "\n";