shill: Framework for asynchronous service side RPC calls.

Use the framework to switch EnterPIN to return asynchronously.

Also, added a few try/catch clauses around DBus proxy calls to ease testing and
debugging. They should go away as we transition to asynchronous proxy calls.

BUG=chromium-os:17263
TEST=unit tests, tested on device

Change-Id: I4177c5b91e23c31838b03689de729932c859a936
Reviewed-on: https://gerrit.chromium.org/gerrit/12541
Tested-by: Darin Petkov <petkov@chromium.org>
Reviewed-by: mukesh agrawal <quiche@chromium.org>
Reviewed-by: Eric Shienbrood <ers@chromium.org>
Commit-Ready: Darin Petkov <petkov@chromium.org>
diff --git a/dbus_adaptor.cc b/dbus_adaptor.cc
index ea1ada9..5d71d95 100644
--- a/dbus_adaptor.cc
+++ b/dbus_adaptor.cc
@@ -349,4 +349,91 @@
   return signature == ::DBus::type<uint32>::sig();
 }
 
+// static
+DBusAdaptor::Returner *DBusAdaptor::Returner::Create(DBusAdaptor *adaptor) {
+  return new Returner(adaptor);
+}
+
+DBusAdaptor::Returner::Returner(DBusAdaptor *adaptor)
+    : adaptor_(adaptor),
+      state_(kStateInitialized) {
+  VLOG(2) << __func__ << " @ " << this;
+}
+
+DBusAdaptor::Returner::~Returner() {
+  CHECK(state_ != kStateDestroyed);
+  VLOG(2) << "Destroying returner @ " << this << " state: " << state_;
+  adaptor_ = NULL;
+  state_ = kStateDestroyed;
+}
+
+void DBusAdaptor::Returner::Return() {
+  VLOG(2) << __func__ << " @ " << this << " state: " << state_;
+  switch (state_) {
+    case kStateInitialized:
+      // Service method is returning right away, without any continuation.
+      state_ = kStateReturned;
+      return;
+    case kStateDelayed: {
+      // This return happens in the continuation.
+      DBus::ObjectAdaptor::Continuation *cont =
+          adaptor_->find_continuation(this);
+      CHECK(cont);
+      adaptor_->return_now(cont);
+      delete this;
+      return;
+    }
+    default:
+      NOTREACHED() << "Unexpected state: " << state_;
+      break;
+  }
+}
+
+void DBusAdaptor::Returner::ReturnError(const Error &error) {
+  VLOG(2) << __func__ << " @ " << this << " state: " << state_;
+  switch (state_) {
+    case kStateInitialized:
+      // Service method is returning right away, without any continuation.
+      error_.CopyFrom(error);
+      state_ = kStateReturned;
+      return;
+    case kStateDelayed: {
+      // This return happens in the continuation.
+      DBus::Error dbus_error;
+      error.ToDBusError(&dbus_error);
+      DBus::ObjectAdaptor::Continuation *cont =
+          adaptor_->find_continuation(this);
+      CHECK(cont);
+      adaptor_->return_error(cont, dbus_error);
+      delete this;
+      return;
+    }
+    default:
+      NOTREACHED() << "Unexpected state: " << state_;
+      break;
+  }
+}
+
+void DBusAdaptor::Returner::DelayOrReturn(DBus::Error *error) {
+  VLOG(2) << __func__ << " @ " << this << " state: " << state_;
+  switch (state_) {
+    case kStateInitialized:
+      // Service method needs continuation so delay the return.
+      state_ = kStateDelayed;
+
+      // return_later does not return. It unwinds the stack up to the dbus-c++
+      // message handler by throwing an exception.
+      adaptor_->return_later(this);
+      return;
+    case kStateReturned:
+      // Service method has returned right away, without any continuation.
+      error_.ToDBusError(error);
+      delete this;
+      return;
+    default:
+      NOTREACHED() << "Unexpected state: " << state_;
+      break;
+  }
+}
+
 }  // namespace shill