Index: ipc/mojo/ipc_channel_mojo.cc |
diff --git a/ipc/mojo/ipc_channel_mojo.cc b/ipc/mojo/ipc_channel_mojo.cc |
index cdb928175dabcfda3104553ad88846b026b952b6..086b420cc52071ef90c7b53cf77249714efd67be 100644 |
--- a/ipc/mojo/ipc_channel_mojo.cc |
+++ b/ipc/mojo/ipc_channel_mojo.cc |
@@ -8,6 +8,7 @@ |
#include "base/bind_helpers.h" |
#include "base/lazy_instance.h" |
#include "ipc/ipc_listener.h" |
+#include "ipc/mojo/ipc_channel_mojo_readers.h" |
#include "mojo/embedder/embedder.h" |
#if defined(OS_POSIX) && !defined(OS_NACL) |
@@ -82,371 +83,10 @@ mojo::embedder::PlatformHandle ToPlatformHandle( |
#endif |
} |
-//------------------------------------------------------------------------------ |
- |
-// 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 |
//------------------------------------------------------------------------------ |
-// A MessagePipeReader implemenation for IPC::Message communication. |
-class ChannelMojo::MessageReader : public internal::MessagePipeReader { |
- public: |
- MessageReader(mojo::ScopedMessagePipeHandle pipe, ChannelMojo* owner) |
- : internal::MessagePipeReader(pipe.Pass()), |
- owner_(owner) {} |
- |
- bool Send(scoped_ptr<Message> message); |
- virtual void OnMessageReceived() OVERRIDE; |
- virtual void OnPipeClosed() OVERRIDE; |
- virtual void OnPipeError(MojoResult error) OVERRIDE; |
- |
- private: |
- ChannelMojo* owner_; |
-}; |
- |
-void ChannelMojo::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) |
- for (size_t i = 0; i < handle_buffer.size(); ++i) { |
- mojo::embedder::ScopedPlatformHandle platform_handle; |
- MojoResult unwrap_result = mojo::embedder::PassWrappedPlatformHandle( |
- handle_buffer[i], &platform_handle); |
- if (unwrap_result != MOJO_RESULT_OK) { |
- DLOG(WARNING) << "Pipe failed to covert handles. Closing: " |
- << unwrap_result; |
- CloseWithError(unwrap_result); |
- return; |
- } |
- |
- bool ok = message.file_descriptor_set()->Add(platform_handle.release().fd); |
- DCHECK(ok); |
- } |
-#else |
- DCHECK(handle_buffer.empty()); |
-#endif |
- |
- message.TraceMessageEnd(); |
- owner_->OnMessageReceived(message); |
-} |
- |
-void ChannelMojo::MessageReader::OnPipeClosed() { |
- if (!owner_) |
- return; |
- owner_->OnPipeClosed(this); |
- owner_ = NULL; |
-} |
- |
-void ChannelMojo::MessageReader::OnPipeError(MojoResult error) { |
- if (!owner_) |
- return; |
- owner_->OnPipeError(this); |
-} |
- |
-bool ChannelMojo::MessageReader::Send(scoped_ptr<Message> message) { |
- DCHECK(IsValid()); |
- |
- message->TraceMessageBegin(); |
- std::vector<MojoHandle> handles; |
-#if defined(OS_POSIX) && !defined(OS_NACL) |
- // We dup() the handles in IPC::Message to transmit. |
- // IPC::FileDescriptorSet has intricate lifecycle semantics |
- // of FDs, so just to dup()-and-own them is the safest option. |
- if (message->HasFileDescriptors()) { |
- FileDescriptorSet* fdset = message->file_descriptor_set(); |
- for (size_t i = 0; i < fdset->size(); ++i) { |
- int fd_to_send = dup(fdset->GetDescriptorAt(i)); |
- if (-1 == fd_to_send) { |
- DPLOG(WARNING) << "Failed to dup FD to transmit."; |
- std::for_each(handles.begin(), handles.end(), &MojoClose); |
- CloseWithError(MOJO_RESULT_UNKNOWN); |
- return false; |
- } |
- |
- MojoHandle wrapped_handle; |
- MojoResult wrap_result = CreatePlatformHandleWrapper( |
- mojo::embedder::ScopedPlatformHandle( |
- mojo::embedder::PlatformHandle(fd_to_send)), |
- &wrapped_handle); |
- if (MOJO_RESULT_OK != wrap_result) { |
- DLOG(WARNING) << "Pipe failed to wrap handles. Closing: " |
- << wrap_result; |
- std::for_each(handles.begin(), handles.end(), &MojoClose); |
- CloseWithError(wrap_result); |
- return false; |
- } |
- |
- handles.push_back(wrapped_handle); |
- } |
- } |
-#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; |
-} |
- |
-//------------------------------------------------------------------------------ |
- |
-// MessagePipeReader implementation for control messages. |
-// Actual message handling is implemented by sublcasses. |
-class ChannelMojo::ControlReader : public internal::MessagePipeReader { |
- public: |
- ControlReader(mojo::ScopedMessagePipeHandle pipe, ChannelMojo* owner) |
- : internal::MessagePipeReader(pipe.Pass()), |
- owner_(owner) {} |
- |
- virtual bool Connect() { return true; } |
- virtual void OnPipeClosed() OVERRIDE; |
- virtual void OnPipeError(MojoResult error) OVERRIDE; |
- |
- protected: |
- ChannelMojo* owner_; |
-}; |
- |
-void ChannelMojo::ControlReader::OnPipeClosed() { |
- if (!owner_) |
- return; |
- owner_->OnPipeClosed(this); |
- owner_ = NULL; |
-} |
- |
-void ChannelMojo::ControlReader::OnPipeError(MojoResult error) { |
- if (!owner_) |
- return; |
- owner_->OnPipeError(this); |
-} |
- |
-//------------------------------------------------------------------------------ |
- |
-// ControlReader for server-side ChannelMojo. |
-class ChannelMojo::ServerControlReader : public ChannelMojo::ControlReader { |
- public: |
- ServerControlReader(mojo::ScopedMessagePipeHandle pipe, ChannelMojo* owner) |
- : ControlReader(pipe.Pass(), owner) { } |
- |
- virtual bool Connect() OVERRIDE; |
- virtual void OnMessageReceived() OVERRIDE; |
- |
- private: |
- MojoResult SendHelloRequest(); |
- MojoResult RespondHelloResponse(); |
- |
- mojo::ScopedMessagePipeHandle message_pipe_; |
-}; |
- |
-bool ChannelMojo::ServerControlReader::Connect() { |
- MojoResult result = SendHelloRequest(); |
- if (result != MOJO_RESULT_OK) { |
- CloseWithError(result); |
- return false; |
- } |
- |
- return true; |
-} |
- |
-MojoResult ChannelMojo::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 ChannelMojo::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 ChannelMojo::ServerControlReader::OnMessageReceived() { |
- MojoResult result = RespondHelloResponse(); |
- if (result != MOJO_RESULT_OK) |
- CloseWithError(result); |
-} |
- |
-//------------------------------------------------------------------------------ |
- |
-// ControlReader for client-side ChannelMojo. |
-class ChannelMojo::ClientControlReader : public ChannelMojo::ControlReader { |
- public: |
- ClientControlReader(mojo::ScopedMessagePipeHandle pipe, ChannelMojo* owner) |
- : ControlReader(pipe.Pass(), owner) {} |
- |
- virtual void OnMessageReceived() OVERRIDE; |
- |
- private: |
- MojoResult RespondHelloRequest(MojoHandle message_channel); |
-}; |
- |
-MojoResult ChannelMojo::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 ChannelMojo::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); |
- } |
-} |
- |
-//------------------------------------------------------------------------------ |
- |
void ChannelMojo::ChannelInfoDeleter::operator()( |
mojo::embedder::ChannelInfo* ptr) const { |
mojo::embedder::DestroyChannelOnIOThread(ptr); |
@@ -458,9 +98,8 @@ void ChannelMojo::ChannelInfoDeleter::operator()( |
scoped_ptr<ChannelMojo> ChannelMojo::Create( |
const ChannelHandle &channel_handle, Mode mode, Listener* listener, |
scoped_refptr<base::TaskRunner> io_thread_task_runner) { |
- return make_scoped_ptr(new ChannelMojo( |
- Channel::Create(channel_handle, mode, g_null_listener.Pointer()), |
- mode, listener, io_thread_task_runner)); |
+ return make_scoped_ptr( |
+ new ChannelMojo(channel_handle, mode, listener, io_thread_task_runner)); |
} |
// static |
@@ -473,11 +112,14 @@ scoped_ptr<ChannelFactory> ChannelMojo::CreateFactory( |
io_thread_task_runner)).PassAs<ChannelFactory>(); |
} |
-ChannelMojo::ChannelMojo( |
- scoped_ptr<Channel> bootstrap, Mode mode, Listener* listener, |
- scoped_refptr<base::TaskRunner> io_thread_task_runner) |
- : bootstrap_(bootstrap.Pass()), |
- mode_(mode), listener_(listener), |
+ChannelMojo::ChannelMojo(const ChannelHandle& channel_handle, |
+ Mode mode, |
+ Listener* listener, |
+ scoped_refptr<base::TaskRunner> io_thread_task_runner) |
+ : bootstrap_( |
+ Channel::Create(channel_handle, mode, g_null_listener.Pointer())), |
+ mode_(mode), |
+ listener_(listener), |
peer_pid_(base::kNullProcessId), |
weak_factory_(this) { |
if (base::MessageLoopProxy::current() == io_thread_task_runner.get()) { |
@@ -504,10 +146,12 @@ void ChannelMojo::InitOnIOThread() { |
switch (mode_) { |
case MODE_SERVER: |
- control_reader_.reset(new ServerControlReader(control_pipe.Pass(), this)); |
+ control_reader_.reset( |
+ new internal::ServerControlReader(control_pipe.Pass(), this)); |
break; |
case MODE_CLIENT: |
- control_reader_.reset(new ClientControlReader(control_pipe.Pass(), this)); |
+ control_reader_.reset( |
+ new internal::ClientControlReader(control_pipe.Pass(), this)); |
break; |
default: |
NOTREACHED(); |
@@ -527,7 +171,8 @@ void ChannelMojo::Close() { |
} |
void ChannelMojo::OnConnected(mojo::ScopedMessagePipeHandle pipe) { |
- message_reader_ = make_scoped_ptr(new MessageReader(pipe.Pass(), this)); |
+ message_reader_ = |
+ make_scoped_ptr(new internal::MessageReader(pipe.Pass(), this)); |
for (size_t i = 0; i < pending_messages_.size(); ++i) { |
message_reader_->Send(make_scoped_ptr(pending_messages_[i])); |
@@ -583,6 +228,62 @@ int ChannelMojo::GetClientFileDescriptor() const { |
int ChannelMojo::TakeClientFileDescriptor() { |
return bootstrap_->TakeClientFileDescriptor(); |
} |
+ |
+// static |
+MojoResult ChannelMojo::WriteToFileDescriptorSet( |
+ const std::vector<MojoHandle>& handle_buffer, |
+ Message* message) { |
+ for (size_t i = 0; i < handle_buffer.size(); ++i) { |
+ mojo::embedder::ScopedPlatformHandle platform_handle; |
+ MojoResult unwrap_result = mojo::embedder::PassWrappedPlatformHandle( |
+ handle_buffer[i], &platform_handle); |
+ if (unwrap_result != MOJO_RESULT_OK) { |
+ DLOG(WARNING) << "Pipe failed to covert handles. Closing: " |
+ << unwrap_result; |
+ return unwrap_result; |
+ } |
+ |
+ bool ok = message->file_descriptor_set()->Add(platform_handle.release().fd); |
+ DCHECK(ok); |
+ } |
+ |
+ return MOJO_RESULT_OK; |
+} |
+ |
+// static |
+MojoResult ChannelMojo::ReadFromFileDescriptorSet( |
+ const Message& message, |
+ std::vector<MojoHandle>* handles) { |
+ // We dup() the handles in IPC::Message to transmit. |
+ // IPC::FileDescriptorSet has intricate lifecycle semantics |
+ // of FDs, so just to dup()-and-own them is the safest option. |
+ if (message.HasFileDescriptors()) { |
+ const FileDescriptorSet* fdset = message.file_descriptor_set(); |
+ for (size_t i = 0; i < fdset->size(); ++i) { |
+ int fd_to_send = dup(fdset->GetDescriptorAt(i)); |
+ if (-1 == fd_to_send) { |
+ DPLOG(WARNING) << "Failed to dup FD to transmit."; |
+ return MOJO_RESULT_UNKNOWN; |
+ } |
+ |
+ MojoHandle wrapped_handle; |
+ MojoResult wrap_result = CreatePlatformHandleWrapper( |
+ mojo::embedder::ScopedPlatformHandle( |
+ mojo::embedder::PlatformHandle(fd_to_send)), |
+ &wrapped_handle); |
+ if (MOJO_RESULT_OK != wrap_result) { |
+ DLOG(WARNING) << "Pipe failed to wrap handles. Closing: " |
+ << wrap_result; |
+ return wrap_result; |
+ } |
+ |
+ handles->push_back(wrapped_handle); |
+ } |
+ } |
+ |
+ return MOJO_RESULT_OK; |
+} |
+ |
#endif // defined(OS_POSIX) && !defined(OS_NACL) |
} // namespace IPC |