Handle mapper introspect race condition

There is a pervasive issue within OpenBMC where a dbus service may be
started and on the bus, but before mapper can introspect it, a dependent
service queries mapper for that objects information.

In most situations a service writer can avoid this by using the
Wants=mapper-wait@-xyz* syntax. This does not work however if two or
more dbus services implement the same dbus object path.

The host_check_main application is one service that is hitting this
issue. It requires the /xyz/openbmc_project/control/host0 object path
which is implemented by two dbus services.

The solution here is to first try mapper, but if that fails to use a
hard coded dbus service name. The value of mapper for this type of
function is up for debate within the community but for now, get a
compromise in that first tries mapper, and if not available tries the hard
coded well-known service name.

Tested:
Verified the following within QEMU:
- Good path works as expected, mapper response used
- GetObject fails for mapper call, successfully used hard coded path
- Service not available on dbus, verified exception reported

Change-Id: I14dfaf2ce43392a19a2a5a3131534f55c6eb6f4a
Signed-off-by: Andrew Geissler <geissonator@yahoo.com>
diff --git a/host_check_main.cpp b/host_check_main.cpp
index 311e6e2..182c501 100644
--- a/host_check_main.cpp
+++ b/host_check_main.cpp
@@ -18,6 +18,7 @@
 constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
 constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
 constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
+constexpr auto CONTROL_HOST_DEFAULT_SVC = "xyz.openbmc_project.Control.Host";
 constexpr auto CONTROL_HOST_PATH = "/xyz/openbmc_project/control/host0";
 constexpr auto CONTROL_HOST_INTERFACE = "xyz.openbmc_project.Control.Host";
 
@@ -71,19 +72,22 @@
     }
     catch (const SdBusError& e)
     {
-        log<level::ERR>("Error in mapper call for control host",
-                        entry("ERROR=%s", e.what()));
-        throw;
+        log<level::INFO>("Error in mapper call for control host, use default "
+                         "service",
+                         entry("ERROR=%s", e.what()));
     }
 
-    if (mapperResponse.empty())
+    std::string host;
+    if (!mapperResponse.empty())
     {
-        log<level::ERR>("Error reading mapper resp for control host");
-        // TODO openbmc/openbmc#851 - Once available, throw returned error
-        throw std::runtime_error("Error reading mapper resp for control host");
+        log<level::DEBUG>("Use mapper response");
+        host = mapperResponse.begin()->first;
     }
-
-    const auto& host = mapperResponse.begin()->first;
+    else
+    {
+        log<level::DEBUG>("Use hard coded host");
+        host = CONTROL_HOST_DEFAULT_SVC;
+    }
 
     auto method = bus.new_method_call(host.c_str(), CONTROL_HOST_PATH,
                                       CONTROL_HOST_INTERFACE, "Execute");