connector.cc revision 0de6073388f4e2780db8536178b129cd8f6ab386
1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "mojo/public/cpp/bindings/lib/connector.h"
6
7#include <assert.h>
8#include <stdlib.h>
9
10#include "mojo/public/cpp/bindings/error_handler.h"
11
12namespace mojo {
13namespace internal {
14
15// ----------------------------------------------------------------------------
16
17Connector::Connector(ScopedMessagePipeHandle message_pipe,
18                     MojoAsyncWaiter* waiter)
19    : error_handler_(NULL),
20      waiter_(waiter),
21      message_pipe_(message_pipe.Pass()),
22      incoming_receiver_(NULL),
23      async_wait_id_(0),
24      error_(false),
25      drop_writes_(false),
26      enforce_errors_from_incoming_receiver_(true) {
27  // Even though we don't have an incoming receiver, we still want to monitor
28  // the message pipe to know if is closed or encounters an error.
29  WaitToReadMore();
30}
31
32Connector::~Connector() {
33  if (async_wait_id_)
34    waiter_->CancelWait(waiter_, async_wait_id_);
35}
36
37void Connector::CloseMessagePipe() {
38  Close(message_pipe_.Pass());
39}
40
41ScopedMessagePipeHandle Connector::ReleaseMessagePipe() {
42  if (async_wait_id_) {
43    waiter_->CancelWait(waiter_, async_wait_id_);
44    async_wait_id_ = 0;
45  }
46  return message_pipe_.Pass();
47}
48
49bool Connector::Accept(Message* message) {
50  assert(message_pipe_.is_valid());
51
52  if (error_)
53    return false;
54
55  if (drop_writes_)
56    return true;
57
58  MojoResult rv = WriteMessageRaw(
59      message_pipe_.get(),
60      message->data(),
61      message->data_num_bytes(),
62      message->mutable_handles()->empty() ? NULL :
63          reinterpret_cast<const MojoHandle*>(
64              &message->mutable_handles()->front()),
65      static_cast<uint32_t>(message->mutable_handles()->size()),
66      MOJO_WRITE_MESSAGE_FLAG_NONE);
67
68  switch (rv) {
69    case MOJO_RESULT_OK:
70      // The handles were successfully transferred, so we don't need the message
71      // to track their lifetime any longer.
72      message->mutable_handles()->clear();
73      break;
74    case MOJO_RESULT_FAILED_PRECONDITION:
75      // There's no point in continuing to write to this pipe since the other
76      // end is gone. Avoid writing any future messages. Hide write failures
77      // from the caller since we'd like them to continue consuming any backlog
78      // of incoming messages before regarding the message pipe as closed.
79      drop_writes_ = true;
80      break;
81    default:
82      // This particular write was rejected, presumably because of bad input.
83      // The pipe is not necessarily in a bad state.
84      return false;
85  }
86  return true;
87}
88
89bool Connector::AcceptWithResponder(Message* message,
90                                    MessageReceiver* responder) {
91  // TODO(darin): Implement this!
92  assert(false);
93  return false;
94}
95
96// static
97void Connector::CallOnHandleReady(void* closure, MojoResult result) {
98  Connector* self = static_cast<Connector*>(closure);
99  self->OnHandleReady(result);
100}
101
102void Connector::OnHandleReady(MojoResult result) {
103  async_wait_id_ = 0;
104
105  if (result == MOJO_RESULT_OK) {
106    ReadMore();
107  } else {
108    error_ = true;
109  }
110
111  if (error_ && error_handler_)
112    error_handler_->OnConnectionError();
113}
114
115void Connector::WaitToReadMore() {
116  async_wait_id_ = waiter_->AsyncWait(waiter_,
117                                      message_pipe_.get().value(),
118                                      MOJO_WAIT_FLAG_READABLE,
119                                      MOJO_DEADLINE_INDEFINITE,
120                                      &Connector::CallOnHandleReady,
121                                      this);
122}
123
124void Connector::ReadMore() {
125  while (true) {
126    bool receiver_result = false;
127    MojoResult rv =  ReadAndDispatchMessage(
128        message_pipe_.get(), incoming_receiver_, &receiver_result);
129    if (rv == MOJO_RESULT_SHOULD_WAIT) {
130      WaitToReadMore();
131      break;
132    }
133    if (rv != MOJO_RESULT_OK ||
134        (enforce_errors_from_incoming_receiver_ && !receiver_result)) {
135      error_ = true;
136      break;
137    }
138  }
139}
140
141}  // namespace internal
142}  // namespace mojo
143