Chromium Code Reviews| Index: ipc/mojo/ipc_channel_mojo_readers.cc |
| diff --git a/ipc/mojo/ipc_channel_mojo_readers.cc b/ipc/mojo/ipc_channel_mojo_readers.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..f599bc2942cf0f355f251cb4e12d6b78fb4c0f2e |
| --- /dev/null |
| +++ b/ipc/mojo/ipc_channel_mojo_readers.cc |
| @@ -0,0 +1,323 @@ |
| +// 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 { |
| + |
| +//------------------------------------------------------------------------------ |
|
yzshen1
2014/09/09 23:52:40
This separator seems unnecessary.
yzshen1
2014/09/10 17:31:09
?
yzshen1
2014/09/10 18:06:16
This is a very trivial suggestion. But if you don'
Hajime Morrita
2014/09/10 20:29:53
Oops again. I overlooked this one. I'm sorry about
|
| + |
| +// 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(message, handle_buffer); |
| + 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 |