summaryrefslogtreecommitdiffstats
path: root/chromium/mojo/public/cpp/bindings/lib/connector.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/mojo/public/cpp/bindings/lib/connector.cc')
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/connector.cc157
1 files changed, 157 insertions, 0 deletions
diff --git a/chromium/mojo/public/cpp/bindings/lib/connector.cc b/chromium/mojo/public/cpp/bindings/lib/connector.cc
new file mode 100644
index 00000000000..aa2c4d12334
--- /dev/null
+++ b/chromium/mojo/public/cpp/bindings/lib/connector.cc
@@ -0,0 +1,157 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "mojo/public/cpp/bindings/lib/connector.h"
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "mojo/public/cpp/bindings/error_handler.h"
+
+namespace mojo {
+namespace internal {
+
+// ----------------------------------------------------------------------------
+
+Connector::Connector(ScopedMessagePipeHandle message_pipe,
+ const MojoAsyncWaiter* waiter)
+ : error_handler_(NULL),
+ waiter_(waiter),
+ message_pipe_(message_pipe.Pass()),
+ incoming_receiver_(NULL),
+ async_wait_id_(0),
+ error_(false),
+ drop_writes_(false),
+ enforce_errors_from_incoming_receiver_(true),
+ destroyed_flag_(NULL) {
+ // Even though we don't have an incoming receiver, we still want to monitor
+ // the message pipe to know if is closed or encounters an error.
+ WaitToReadMore();
+}
+
+Connector::~Connector() {
+ if (destroyed_flag_)
+ *destroyed_flag_ = true;
+
+ if (async_wait_id_)
+ waiter_->CancelWait(async_wait_id_);
+}
+
+void Connector::CloseMessagePipe() {
+ Close(message_pipe_.Pass());
+}
+
+ScopedMessagePipeHandle Connector::PassMessagePipe() {
+ if (async_wait_id_) {
+ waiter_->CancelWait(async_wait_id_);
+ async_wait_id_ = 0;
+ }
+ return message_pipe_.Pass();
+}
+
+bool Connector::Accept(Message* message) {
+ assert(message_pipe_.is_valid());
+
+ if (error_)
+ return false;
+
+ if (drop_writes_)
+ return true;
+
+ MojoResult rv = WriteMessageRaw(
+ message_pipe_.get(),
+ message->data(),
+ message->data_num_bytes(),
+ message->mutable_handles()->empty() ? NULL :
+ reinterpret_cast<const MojoHandle*>(
+ &message->mutable_handles()->front()),
+ static_cast<uint32_t>(message->mutable_handles()->size()),
+ MOJO_WRITE_MESSAGE_FLAG_NONE);
+
+ switch (rv) {
+ case MOJO_RESULT_OK:
+ // The handles were successfully transferred, so we don't need the message
+ // to track their lifetime any longer.
+ message->mutable_handles()->clear();
+ break;
+ case MOJO_RESULT_FAILED_PRECONDITION:
+ // There's no point in continuing to write to this pipe since the other
+ // end is gone. Avoid writing any future messages. Hide write failures
+ // from the caller since we'd like them to continue consuming any backlog
+ // of incoming messages before regarding the message pipe as closed.
+ drop_writes_ = true;
+ break;
+ default:
+ // This particular write was rejected, presumably because of bad input.
+ // The pipe is not necessarily in a bad state.
+ return false;
+ }
+ return true;
+}
+
+// static
+void Connector::CallOnHandleReady(void* closure, MojoResult result) {
+ Connector* self = static_cast<Connector*>(closure);
+ self->OnHandleReady(result);
+}
+
+void Connector::OnHandleReady(MojoResult result) {
+ assert(async_wait_id_ != 0);
+ async_wait_id_ = 0;
+
+ if (result == MOJO_RESULT_OK) {
+ // Return immediately if |this| was destroyed. Do not touch any members!
+ if (!ReadMore())
+ return;
+ } else {
+ error_ = true;
+ }
+
+ if (error_ && error_handler_)
+ error_handler_->OnConnectionError();
+}
+
+void Connector::WaitToReadMore() {
+ async_wait_id_ = waiter_->AsyncWait(message_pipe_.get().value(),
+ MOJO_HANDLE_SIGNAL_READABLE,
+ MOJO_DEADLINE_INDEFINITE,
+ &Connector::CallOnHandleReady,
+ this);
+}
+
+bool Connector::ReadMore() {
+ while (true) {
+ bool receiver_result = false;
+
+ // Detect if |this| was destroyed during message dispatch. Allow for the
+ // possibility of re-entering ReadMore() through message dispatch.
+ bool was_destroyed_during_dispatch = false;
+ bool* previous_destroyed_flag = destroyed_flag_;
+ destroyed_flag_ = &was_destroyed_during_dispatch;
+
+ MojoResult rv = ReadAndDispatchMessage(
+ message_pipe_.get(), incoming_receiver_, &receiver_result);
+
+ if (was_destroyed_during_dispatch) {
+ if (previous_destroyed_flag)
+ *previous_destroyed_flag = true; // Propagate flag.
+ return false;
+ }
+ destroyed_flag_ = previous_destroyed_flag;
+
+ if (rv == MOJO_RESULT_SHOULD_WAIT) {
+ WaitToReadMore();
+ break;
+ }
+ if (rv != MOJO_RESULT_OK ||
+ (enforce_errors_from_incoming_receiver_ && !receiver_result)) {
+ error_ = true;
+ break;
+ }
+ }
+ return true;
+}
+
+} // namespace internal
+} // namespace mojo