summaryrefslogtreecommitdiffstats
path: root/ipc/mojo/ipc_channel_mojo_readers.cc
diff options
context:
space:
mode:
authormorrita <morrita@chromium.org>2014-09-11 12:06:29 -0700
committerCommit bot <commit-bot@chromium.org>2014-09-11 19:09:46 +0000
commit3b41d6ca4deea242d5fa916d4c4864fd08bddf06 (patch)
treeb8bda2dae559e03c4a033135a0e5e9542166a088 /ipc/mojo/ipc_channel_mojo_readers.cc
parentba249ef277f2fe628f82b8280f70491d0d4a535a (diff)
downloadchromium_src-3b41d6ca4deea242d5fa916d4c4864fd08bddf06.zip
chromium_src-3b41d6ca4deea242d5fa916d4c4864fd08bddf06.tar.gz
chromium_src-3b41d6ca4deea242d5fa916d4c4864fd08bddf06.tar.bz2
Refactoring: Move MessagePipeReader subclasess out from ChannelMojo
There are a few MessagePipeReader sublcasses defined as inter-classes of ChannelMojo. This makes it harder to hook them for unit testing. This CL moves these classes their own file. Now unittest can define subclasses of these to hook some behavor for testing. This is a preparation for a crash fix. BUG=410813 TEST=none R=viettrungluu@chromium.org,yzshen@chromium.org Review URL: https://codereview.chromium.org/559723002 Cr-Commit-Position: refs/heads/master@{#294439}
Diffstat (limited to 'ipc/mojo/ipc_channel_mojo_readers.cc')
-rw-r--r--ipc/mojo/ipc_channel_mojo_readers.cc321
1 files changed, 321 insertions, 0 deletions
diff --git a/ipc/mojo/ipc_channel_mojo_readers.cc b/ipc/mojo/ipc_channel_mojo_readers.cc
new file mode 100644
index 0000000..7af96f8
--- /dev/null
+++ b/ipc/mojo/ipc_channel_mojo_readers.cc
@@ -0,0 +1,321 @@
+// Copyright 2014 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 "ipc/mojo/ipc_channel_mojo_readers.h"
+
+#include "ipc/mojo/ipc_channel_mojo.h"
+#include "mojo/embedder/embedder.h"
+
+#if defined(OS_POSIX) && !defined(OS_NACL)
+#include "ipc/file_descriptor_set_posix.h"
+#endif
+
+namespace IPC {
+namespace internal {
+
+namespace {
+
+// TODO(morrita): This should be built using higher-level Mojo construct
+// for clarity and extensibility.
+class HelloMessage {
+ public:
+ static Pickle CreateRequest(int32 pid) {
+ Pickle request;
+ request.WriteString(kHelloRequestMagic);
+ request.WriteInt(pid);
+ return request;
+ }
+
+ static bool ReadRequest(Pickle& pickle, int32* pid) {
+ PickleIterator iter(pickle);
+ std::string hello;
+ if (!iter.ReadString(&hello)) {
+ DLOG(WARNING) << "Failed to Read magic string.";
+ return false;
+ }
+
+ if (hello != kHelloRequestMagic) {
+ DLOG(WARNING) << "Magic mismatch:" << hello;
+ return false;
+ }
+
+ int read_pid;
+ if (!iter.ReadInt(&read_pid)) {
+ DLOG(WARNING) << "Failed to Read PID.";
+ return false;
+ }
+
+ *pid = read_pid;
+ return true;
+ }
+
+ static Pickle CreateResponse(int32 pid) {
+ Pickle request;
+ request.WriteString(kHelloResponseMagic);
+ request.WriteInt(pid);
+ return request;
+ }
+
+ static bool ReadResponse(Pickle& pickle, int32* pid) {
+ PickleIterator iter(pickle);
+ std::string hello;
+ if (!iter.ReadString(&hello)) {
+ DLOG(WARNING) << "Failed to read magic string.";
+ return false;
+ }
+
+ if (hello != kHelloResponseMagic) {
+ DLOG(WARNING) << "Magic mismatch:" << hello;
+ return false;
+ }
+
+ int read_pid;
+ if (!iter.ReadInt(&read_pid)) {
+ DLOG(WARNING) << "Failed to read PID.";
+ return false;
+ }
+
+ *pid = read_pid;
+ return true;
+ }
+
+ private:
+ static const char* kHelloRequestMagic;
+ static const char* kHelloResponseMagic;
+};
+
+const char* HelloMessage::kHelloRequestMagic = "MREQ";
+const char* HelloMessage::kHelloResponseMagic = "MRES";
+
+} // namespace
+
+//------------------------------------------------------------------------------
+
+MessageReader::MessageReader(mojo::ScopedMessagePipeHandle pipe,
+ ChannelMojo* owner)
+ : internal::MessagePipeReader(pipe.Pass()), owner_(owner) {
+}
+
+void MessageReader::OnMessageReceived() {
+ Message message(data_buffer().empty() ? "" : &data_buffer()[0],
+ static_cast<uint32>(data_buffer().size()));
+
+ std::vector<MojoHandle> handle_buffer;
+ TakeHandleBuffer(&handle_buffer);
+#if defined(OS_POSIX) && !defined(OS_NACL)
+ MojoResult write_result =
+ ChannelMojo::WriteToFileDescriptorSet(handle_buffer, &message);
+ if (write_result != MOJO_RESULT_OK) {
+ CloseWithError(write_result);
+ return;
+ }
+#else
+ DCHECK(handle_buffer.empty());
+#endif
+
+ message.TraceMessageEnd();
+ owner_->OnMessageReceived(message);
+}
+
+void MessageReader::OnPipeClosed() {
+ if (!owner_)
+ return;
+ owner_->OnPipeClosed(this);
+ owner_ = NULL;
+}
+
+void MessageReader::OnPipeError(MojoResult error) {
+ if (!owner_)
+ return;
+ owner_->OnPipeError(this);
+}
+
+bool MessageReader::Send(scoped_ptr<Message> message) {
+ DCHECK(IsValid());
+
+ message->TraceMessageBegin();
+ std::vector<MojoHandle> handles;
+#if defined(OS_POSIX) && !defined(OS_NACL)
+ MojoResult read_result =
+ ChannelMojo::ReadFromFileDescriptorSet(*message, &handles);
+ if (read_result != MOJO_RESULT_OK) {
+ std::for_each(handles.begin(), handles.end(), &MojoClose);
+ CloseWithError(read_result);
+ return false;
+ }
+#endif
+ MojoResult write_result =
+ MojoWriteMessage(handle(),
+ message->data(),
+ static_cast<uint32>(message->size()),
+ handles.empty() ? NULL : &handles[0],
+ static_cast<uint32>(handles.size()),
+ MOJO_WRITE_MESSAGE_FLAG_NONE);
+ if (MOJO_RESULT_OK != write_result) {
+ std::for_each(handles.begin(), handles.end(), &MojoClose);
+ CloseWithError(write_result);
+ return false;
+ }
+
+ return true;
+}
+
+//------------------------------------------------------------------------------
+
+ControlReader::ControlReader(mojo::ScopedMessagePipeHandle pipe,
+ ChannelMojo* owner)
+ : internal::MessagePipeReader(pipe.Pass()), owner_(owner) {
+}
+
+void ControlReader::OnPipeClosed() {
+ if (!owner_)
+ return;
+ owner_->OnPipeClosed(this);
+ owner_ = NULL;
+}
+
+void ControlReader::OnPipeError(MojoResult error) {
+ if (!owner_)
+ return;
+ owner_->OnPipeError(this);
+}
+
+bool ControlReader::Connect() {
+ return true;
+}
+
+//------------------------------------------------------------------------------
+
+ServerControlReader::ServerControlReader(mojo::ScopedMessagePipeHandle pipe,
+ ChannelMojo* owner)
+ : ControlReader(pipe.Pass(), owner) {
+}
+
+ServerControlReader::~ServerControlReader() {
+}
+
+bool ServerControlReader::Connect() {
+ MojoResult result = SendHelloRequest();
+ if (result != MOJO_RESULT_OK) {
+ CloseWithError(result);
+ return false;
+ }
+
+ return true;
+}
+
+MojoResult ServerControlReader::SendHelloRequest() {
+ DCHECK(IsValid());
+ DCHECK(!message_pipe_.is_valid());
+
+ mojo::ScopedMessagePipeHandle self;
+ mojo::ScopedMessagePipeHandle peer;
+ MojoResult create_result =
+ mojo::CreateMessagePipe(NULL, &message_pipe_, &peer);
+ if (MOJO_RESULT_OK != create_result) {
+ DLOG(WARNING) << "mojo::CreateMessagePipe failed: " << create_result;
+ return create_result;
+ }
+
+ MojoHandle peer_to_send = peer.get().value();
+ Pickle request = HelloMessage::CreateRequest(owner_->GetSelfPID());
+ MojoResult write_result =
+ MojoWriteMessage(handle(),
+ request.data(),
+ static_cast<uint32>(request.size()),
+ &peer_to_send,
+ 1,
+ MOJO_WRITE_MESSAGE_FLAG_NONE);
+ if (MOJO_RESULT_OK != write_result) {
+ DLOG(WARNING) << "Writing Hello request failed: " << create_result;
+ return write_result;
+ }
+
+ // |peer| is sent and no longer owned by |this|.
+ (void)peer.release();
+ return MOJO_RESULT_OK;
+}
+
+MojoResult ServerControlReader::RespondHelloResponse() {
+ Pickle request(data_buffer().empty() ? "" : &data_buffer()[0],
+ static_cast<uint32>(data_buffer().size()));
+
+ int32 read_pid = 0;
+ if (!HelloMessage::ReadResponse(request, &read_pid)) {
+ DLOG(ERROR) << "Failed to parse Hello response.";
+ return MOJO_RESULT_UNKNOWN;
+ }
+
+ base::ProcessId pid = static_cast<base::ProcessId>(read_pid);
+ owner_->set_peer_pid(pid);
+ owner_->OnConnected(message_pipe_.Pass());
+ return MOJO_RESULT_OK;
+}
+
+void ServerControlReader::OnMessageReceived() {
+ MojoResult result = RespondHelloResponse();
+ if (result != MOJO_RESULT_OK)
+ CloseWithError(result);
+}
+
+//------------------------------------------------------------------------------
+
+ClientControlReader::ClientControlReader(mojo::ScopedMessagePipeHandle pipe,
+ ChannelMojo* owner)
+ : ControlReader(pipe.Pass(), owner) {
+}
+
+MojoResult ClientControlReader::RespondHelloRequest(
+ MojoHandle message_channel) {
+ DCHECK(IsValid());
+
+ mojo::ScopedMessagePipeHandle received_pipe(
+ (mojo::MessagePipeHandle(message_channel)));
+
+ int32 read_request = 0;
+ Pickle request(data_buffer().empty() ? "" : &data_buffer()[0],
+ static_cast<uint32>(data_buffer().size()));
+ if (!HelloMessage::ReadRequest(request, &read_request)) {
+ DLOG(ERROR) << "Hello request has wrong magic.";
+ return MOJO_RESULT_UNKNOWN;
+ }
+
+ base::ProcessId pid = read_request;
+ Pickle response = HelloMessage::CreateResponse(owner_->GetSelfPID());
+ MojoResult write_result =
+ MojoWriteMessage(handle(),
+ response.data(),
+ static_cast<uint32>(response.size()),
+ NULL,
+ 0,
+ MOJO_WRITE_MESSAGE_FLAG_NONE);
+ if (MOJO_RESULT_OK != write_result) {
+ DLOG(ERROR) << "Writing Hello response failed: " << write_result;
+ return write_result;
+ }
+
+ owner_->set_peer_pid(pid);
+ owner_->OnConnected(received_pipe.Pass());
+ return MOJO_RESULT_OK;
+}
+
+void ClientControlReader::OnMessageReceived() {
+ std::vector<MojoHandle> handle_buffer;
+ TakeHandleBuffer(&handle_buffer);
+ if (handle_buffer.size() != 1) {
+ DLOG(ERROR) << "Hello request doesn't contains required handle: "
+ << handle_buffer.size();
+ CloseWithError(MOJO_RESULT_UNKNOWN);
+ return;
+ }
+
+ MojoResult result = RespondHelloRequest(handle_buffer[0]);
+ if (result != MOJO_RESULT_OK) {
+ DLOG(ERROR) << "Failed to respond Hello request. Closing: " << result;
+ CloseWithError(result);
+ }
+}
+
+} // namespace internal
+} // namespace IPC