Change yield_method_call to be no-throw

The yield_method_call() would throw despite the inferred promise that it
would not, because the caller could attach an error_code to the yield
object. But that would only protect from the dbus method call itself.
When it came time to unpack the response, the read(...) method call
would throw if the received types did not match the expected types. Now,
the method forces you to pass in an error_code and it will always return
the appropriate error instead of throw.

Tested-by: run asio-example to see that it works as expected:
    # /tmp/asio-example
    voidBar() -> 42
    async_send callback
    error with async_send
    async_method_call callback
    /org/openbmc/control/bmc0
    /org/openbmc/control/flash/bmc
    fooYield(yield, 41)...
    ipmiInterface:execute(61)
    ipmi call returns OK!
    fooYield(yield, 41)...
    foo(41) -> 42
    async call to Properties.Get serialized via yield OK!
    foo(41) -> 42
    yielding call to foo OK! (-> 42)
    TestYieldFunction return 42
    yielding call to foo OK! (-> 42)
    yielding call to TestYieldFunction serialized via yield OK!
    async call to Properties.Get serialized via yield OK!
    *** tick ***
    *** tock ***
    *** tick ***
    *** tick ***
    *** tick ***
    *** tick ***
    *** tick ***

Change-Id: Iea43acd432107b4149f8e549310cfce2518cbc1d
Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com>
diff --git a/example/asio-example.cpp b/example/asio-example.cpp
index 0e20f41..2cd1323 100644
--- a/example/asio-example.cpp
+++ b/example/asio-example.cpp
@@ -28,7 +28,7 @@
     boost::system::error_code ec;
     std::cout << "fooYield(yield, " << test << ")...\n";
     int testCount = conn->yield_method_call<int>(
-        yield[ec], "xyz.openbmc_project.asio-test", "/xyz/openbmc_project/test",
+        yield, ec, "xyz.openbmc_project.asio-test", "/xyz/openbmc_project/test",
         "xyz.openbmc_project.test", "TestFunction", test);
     if (ec || testCount != (test + 1))
     {
@@ -58,12 +58,12 @@
 {
     boost::system::error_code ec;
     variant testValue;
-    conn->yield_method_call<>(yield[ec], "xyz.openbmc_project.asio-test",
+    conn->yield_method_call<>(yield, ec, "xyz.openbmc_project.asio-test",
                               "/xyz/openbmc_project/test",
                               "org.freedesktop.DBus.Properties", "Set",
                               "xyz.openbmc_project.test", "int", variant(24));
     testValue = conn->yield_method_call<variant>(
-        yield[ec], "xyz.openbmc_project.asio-test", "/xyz/openbmc_project/test",
+        yield, ec, "xyz.openbmc_project.asio-test", "/xyz/openbmc_project/test",
         "org.freedesktop.DBus.Properties", "Get", "xyz.openbmc_project.test",
         "int");
     if (!ec && std::get<int>(testValue) == 24)
@@ -75,11 +75,11 @@
         std::cout << "ec = " << ec << ": " << std::get<int>(testValue) << "\n";
     }
     conn->yield_method_call<void>(
-        yield[ec], "xyz.openbmc_project.asio-test", "/xyz/openbmc_project/test",
+        yield, ec, "xyz.openbmc_project.asio-test", "/xyz/openbmc_project/test",
         "org.freedesktop.DBus.Properties", "Set", "xyz.openbmc_project.test",
         "int", variant(42));
     testValue = conn->yield_method_call<variant>(
-        yield[ec], "xyz.openbmc_project.asio-test", "/xyz/openbmc_project/test",
+        yield, ec, "xyz.openbmc_project.asio-test", "/xyz/openbmc_project/test",
         "org.freedesktop.DBus.Properties", "Get", "xyz.openbmc_project.test",
         "int");
     if (!ec && std::get<int>(testValue) == 42)
@@ -149,7 +149,7 @@
     try
     {
         testValue = conn->yield_method_call<int>(
-            yield[ec], "xyz.openbmc_project.asio-test",
+            yield, ec, "xyz.openbmc_project.asio-test",
             "/xyz/openbmc_project/test", "xyz.openbmc_project.test",
             "TestYieldFunction", int(41));
     }
diff --git a/sdbusplus/asio/connection.hpp b/sdbusplus/asio/connection.hpp
index 8590627..9b570be 100644
--- a/sdbusplus/asio/connection.hpp
+++ b/sdbusplus/asio/connection.hpp
@@ -149,9 +149,8 @@
     /** @brief Perform a yielding asynchronous method call, with input
      *         parameter packing and return value unpacking
      *
-     *  @param[in] yield - A yield context to async block upon. To catch errors
-     *                     for the call, call this function with 'yield[ec]',
-     *                     thus attaching an error code to the yield context
+     *  @param[in] yield - A yield context to async block upon.
+     *  @param[in] ec - an error code that will be set for any errors
      *  @param[in] service - The service to call.
      *  @param[in] objpath - The object's path for the call.
      *  @param[in] interf - The object's interface to call.
@@ -162,6 +161,7 @@
      */
     template <typename... RetTypes, typename... InputArgs>
     auto yield_method_call(boost::asio::yield_context yield,
+                           boost::system::error_code& ec,
                            const std::string& service,
                            const std::string& objpath,
                            const std::string& interf, const std::string& method,
@@ -170,7 +170,7 @@
         message::message m = new_method_call(service.c_str(), objpath.c_str(),
                                              interf.c_str(), method.c_str());
         m.append(a...);
-        message::message r = async_send(m, yield);
+        message::message r = async_send(m, yield[ec]);
         if constexpr (sizeof...(RetTypes) == 0)
         {
             // void return
@@ -187,8 +187,21 @@
             {
                 // single item return
                 utility::first_type<RetTypes...> responseData;
-                // this will throw if the signature of r != RetType
-                r.read(responseData);
+                // before attempting to read, check ec and bail on error
+                if (ec)
+                {
+                    return responseData;
+                }
+                try
+                {
+                    r.read(responseData);
+                }
+                catch (const std::exception& e)
+                {
+                    ec = boost::system::errc::make_error_code(
+                        boost::system::errc::invalid_argument);
+                    // responseData will be default-constructed...
+                }
                 return responseData;
             }
         }
@@ -196,8 +209,21 @@
         {
             // tuple of things to return
             std::tuple<RetTypes...> responseData;
-            // this will throw if the signature of r != RetType
-            r.read(responseData);
+            // before attempting to read, check ec and bail on error
+            if (ec)
+            {
+                return responseData;
+            }
+            try
+            {
+                r.read(responseData);
+            }
+            catch (const std::exception& e)
+            {
+                ec = boost::system::errc::make_error_code(
+                    boost::system::errc::invalid_argument);
+                // responseData will be default-constructed...
+            }
             return responseData;
         }
     }