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