14e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
24e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
34e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// found in the LICENSE file.
44e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
54e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "mojo/system/message_pipe.h"
64e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
74e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/logging.h"
81320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "mojo/system/channel_endpoint.h"
94e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "mojo/system/local_message_pipe_endpoint.h"
104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "mojo/system/message_in_transit.h"
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "mojo/system/message_pipe_dispatcher.h"
124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "mojo/system/message_pipe_endpoint.h"
13f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "mojo/system/proxy_message_pipe_endpoint.h"
144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace mojo {
164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace system {
174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// static
191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciMessagePipe* MessagePipe::CreateLocalLocal() {
201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  MessagePipe* message_pipe = new MessagePipe();
211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  message_pipe->endpoints_[0].reset(new LocalMessagePipeEndpoint());
221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  message_pipe->endpoints_[1].reset(new LocalMessagePipeEndpoint());
231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return message_pipe;
244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// static
271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciMessagePipe* MessagePipe::CreateLocalProxy(
281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    scoped_refptr<ChannelEndpoint>* channel_endpoint) {
291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(!channel_endpoint->get());  // Not technically wrong, but unlikely.
301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  MessagePipe* message_pipe = new MessagePipe();
311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  message_pipe->endpoints_[0].reset(new LocalMessagePipeEndpoint());
321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  *channel_endpoint = new ChannelEndpoint(message_pipe, 1);
331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  message_pipe->endpoints_[1].reset(
341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      new ProxyMessagePipeEndpoint(channel_endpoint->get()));
351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return message_pipe;
361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// static
391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciMessagePipe* MessagePipe::CreateProxyLocal(
401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    scoped_refptr<ChannelEndpoint>* channel_endpoint) {
411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(!channel_endpoint->get());  // Not technically wrong, but unlikely.
421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  MessagePipe* message_pipe = new MessagePipe();
431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  *channel_endpoint = new ChannelEndpoint(message_pipe, 0);
441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  message_pipe->endpoints_[0].reset(
451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      new ProxyMessagePipeEndpoint(channel_endpoint->get()));
461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  message_pipe->endpoints_[1].reset(new LocalMessagePipeEndpoint());
471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return message_pipe;
484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
50f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// static
51f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)unsigned MessagePipe::GetPeerPort(unsigned port) {
52f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(port == 0 || port == 1);
53f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return port ^ 1;
54f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
55f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
56a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)MessagePipeEndpoint::Type MessagePipe::GetType(unsigned port) {
57a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(port == 0 || port == 1);
58a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::AutoLock locker(lock_);
59cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(endpoints_[port]);
60a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
61a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return endpoints_[port]->GetType();
62a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
63a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void MessagePipe::CancelAllWaiters(unsigned port) {
654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK(port == 0 || port == 1);
664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  base::AutoLock locker(lock_);
68cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(endpoints_[port]);
694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  endpoints_[port]->CancelAllWaiters();
704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void MessagePipe::Close(unsigned port) {
734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK(port == 0 || port == 1);
744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
75f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  unsigned destination_port = GetPeerPort(port);
764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  base::AutoLock locker(lock_);
78cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(endpoints_[port]);
794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  endpoints_[port]->Close();
81cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (endpoints_[destination_port]) {
820529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if (!endpoints_[destination_port]->OnPeerClose())
830529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      endpoints_[destination_port].reset();
840529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  endpoints_[port].reset();
864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// TODO(vtl): Handle flags.
894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)MojoResult MessagePipe::WriteMessage(
904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    unsigned port,
915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    UserPointer<const void> bytes,
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    uint32_t num_bytes,
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::vector<DispatcherTransport>* transports,
944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    MojoWriteMessageFlags flags) {
954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK(port == 0 || port == 1);
965c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  return EnqueueMessageInternal(
97f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      GetPeerPort(port),
98a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      make_scoped_ptr(new MessageInTransit(
99f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          MessageInTransit::kTypeMessagePipeEndpoint,
100f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          MessageInTransit::kSubtypeMessagePipeEndpointData,
101010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)          num_bytes,
102010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)          bytes)),
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      transports);
1044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
106010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)MojoResult MessagePipe::ReadMessage(unsigned port,
1075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                    UserPointer<void> bytes,
1085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                    UserPointer<uint32_t> num_bytes,
109010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                    DispatcherVector* dispatchers,
110010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                    uint32_t* num_dispatchers,
111010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                    MojoReadMessageFlags flags) {
1124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK(port == 0 || port == 1);
1134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  base::AutoLock locker(lock_);
115cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(endpoints_[port]);
1164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return endpoints_[port]->ReadMessage(
1185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      bytes, num_bytes, dispatchers, num_dispatchers, flags);
1195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)HandleSignalsState MessagePipe::GetHandleSignalsState(unsigned port) const {
1225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK(port == 0 || port == 1);
1235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  base::AutoLock locker(const_cast<base::Lock&>(lock_));
1255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK(endpoints_[port]);
1265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return endpoints_[port]->GetHandleSignalsState();
1284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)MojoResult MessagePipe::AddWaiter(unsigned port,
1314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                  Waiter* waiter,
132f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                  MojoHandleSignals signals,
1335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                  uint32_t context,
1345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                  HandleSignalsState* signals_state) {
1354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK(port == 0 || port == 1);
1364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  base::AutoLock locker(lock_);
138cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(endpoints_[port]);
1394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return endpoints_[port]->AddWaiter(waiter, signals, context, signals_state);
1414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void MessagePipe::RemoveWaiter(unsigned port,
1445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               Waiter* waiter,
1455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               HandleSignalsState* signals_state) {
1464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK(port == 0 || port == 1);
1474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  base::AutoLock locker(lock_);
149cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(endpoints_[port]);
1504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  endpoints_[port]->RemoveWaiter(waiter, signals_state);
1524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciscoped_refptr<ChannelEndpoint> MessagePipe::ConvertLocalToProxy(unsigned port) {
155a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(port == 0 || port == 1);
156a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
157a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::AutoLock locker(lock_);
158cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(endpoints_[port]);
159a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK_EQ(endpoints_[port]->GetType(), MessagePipeEndpoint::kTypeLocal);
160a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // TODO(vtl): Allowing this case is a temporary hack. It'll set up a
1621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // |MessagePipe| with two proxy endpoints, which will then act as a proxy
1631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // (rather than trying to connect the two ends directly).
1641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DLOG_IF(WARNING,
1651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          !!endpoints_[GetPeerPort(port)] &&
1661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci              endpoints_[GetPeerPort(port)]->GetType() !=
1671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                  MessagePipeEndpoint::kTypeLocal)
1681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      << "Direct message pipe passing across multiple channels not yet "
1691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci         "implemented; will proxy";
170a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  scoped_ptr<MessagePipeEndpoint> old_endpoint(endpoints_[port].Pass());
1721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  scoped_refptr<ChannelEndpoint> channel_endpoint(
1731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      new ChannelEndpoint(this, port));
1741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  endpoints_[port].reset(new ProxyMessagePipeEndpoint(channel_endpoint.get()));
1751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  channel_endpoint->TakeMessages(static_cast<LocalMessagePipeEndpoint*>(
1761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                     old_endpoint.get())->message_queue());
1771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  old_endpoint->Close();
178a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return channel_endpoint;
180a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
181a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)MojoResult MessagePipe::EnqueueMessage(unsigned port,
1835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                       scoped_ptr<MessageInTransit> message) {
1841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return EnqueueMessageInternal(port, message.Pass(), nullptr);
1850529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
1860529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1870529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid MessagePipe::OnRemove(unsigned port) {
1880529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  unsigned destination_port = GetPeerPort(port);
1890529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1900529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  base::AutoLock locker(lock_);
1910529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // A |OnPeerClose()| can come in first, before |OnRemove()| gets called.
192cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!endpoints_[port])
1930529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return;
1940529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
195cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (endpoints_[destination_port]) {
1960529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if (!endpoints_[destination_port]->OnPeerClose())
1970529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      endpoints_[destination_port].reset();
1980529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
1990529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  endpoints_[port].reset();
200f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
201f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
2021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciMessagePipe::MessagePipe() {
2031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
2041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)MessagePipe::~MessagePipe() {
2064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Owned by the dispatchers. The owning dispatchers should only release us via
2074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // their |Close()| method, which should inform us of being closed via our
2084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // |Close()|. Thus these should already be null.
209cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(!endpoints_[0]);
210cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(!endpoints_[1]);
2114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
2124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuMojoResult MessagePipe::EnqueueMessageInternal(
2145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    unsigned port,
2155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    scoped_ptr<MessageInTransit> message,
2165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    std::vector<DispatcherTransport>* transports) {
2175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DCHECK(port == 0 || port == 1);
218cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(message);
2195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (message->type() == MessageInTransit::kTypeMessagePipe) {
2215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    DCHECK(!transports);
2225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return HandleControlMessage(port, message.Pass());
2235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
2245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DCHECK_EQ(message->type(), MessageInTransit::kTypeMessagePipeEndpoint);
2265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  base::AutoLock locker(lock_);
228cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(endpoints_[GetPeerPort(port)]);
2295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // The destination port need not be open, unlike the source port.
231cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!endpoints_[port])
2325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return MOJO_RESULT_FAILED_PRECONDITION;
2335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (transports) {
2355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    MojoResult result = AttachTransportsNoLock(port, message.get(), transports);
2365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    if (result != MOJO_RESULT_OK)
2375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      return result;
2385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
2395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // The endpoint's |EnqueueMessage()| may not report failure.
2415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  endpoints_[port]->EnqueueMessage(message.Pass());
2425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  return MOJO_RESULT_OK;
2435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
2445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuMojoResult MessagePipe::AttachTransportsNoLock(
2465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    unsigned port,
2475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    MessageInTransit* message,
2485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    std::vector<DispatcherTransport>* transports) {
2495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DCHECK(!message->has_dispatchers());
2505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // You're not allowed to send either handle to a message pipe over the message
2525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // pipe, so check for this. (The case of trying to write a handle to itself is
2535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // taken care of by |Core|. That case kind of makes sense, but leads to
2545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // complications if, e.g., both sides try to do the same thing with their
2555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // respective handles simultaneously. The other case, of trying to write the
2565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // peer handle to a handle, doesn't make sense -- since no handle will be
2575c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // available to read the message from.)
2585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  for (size_t i = 0; i < transports->size(); i++) {
2595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    if (!(*transports)[i].is_valid())
2605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      continue;
2615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    if ((*transports)[i].GetType() == Dispatcher::kTypeMessagePipe) {
2625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      MessagePipeDispatcherTransport mp_transport((*transports)[i]);
2635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      if (mp_transport.GetMessagePipe() == this) {
2645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        // The other case should have been disallowed by |Core|. (Note: |port|
2655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        // is the peer port of the handle given to |WriteMessage()|.)
2665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        DCHECK_EQ(mp_transport.GetPort(), port);
2675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        return MOJO_RESULT_INVALID_ARGUMENT;
2685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      }
2695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    }
2705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
2715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // Clone the dispatchers and attach them to the message. (This must be done as
2735c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // a separate loop, since we want to leave the dispatchers alone on failure.)
274010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  scoped_ptr<DispatcherVector> dispatchers(new DispatcherVector());
2755c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  dispatchers->reserve(transports->size());
2765c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  for (size_t i = 0; i < transports->size(); i++) {
2775c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    if ((*transports)[i].is_valid()) {
2785c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      dispatchers->push_back(
2795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu          (*transports)[i].CreateEquivalentDispatcherAndClose());
2805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    } else {
2815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      LOG(WARNING) << "Enqueueing null dispatcher";
2825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      dispatchers->push_back(scoped_refptr<Dispatcher>());
2835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    }
2845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
2855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  message->SetDispatchers(dispatchers.Pass());
2865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  return MOJO_RESULT_OK;
2875c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
2885c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
289a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)MojoResult MessagePipe::HandleControlMessage(
2900529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    unsigned /*port*/,
291a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    scoped_ptr<MessageInTransit> message) {
292a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  LOG(WARNING) << "Unrecognized MessagePipe control message subtype "
293a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)               << message->subtype();
294a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return MOJO_RESULT_UNKNOWN;
295f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
296f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
2974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}  // namespace system
2984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}  // namespace mojo
299