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/message.h"
6
7 #include <stddef.h>
8 #include <stdint.h>
9 #include <stdlib.h>
10
11 #include <algorithm>
12 #include <utility>
13
14 #include "base/logging.h"
15 #include "base/strings/stringprintf.h"
16
17 namespace mojo {
18
Message()19 Message::Message() {
20 }
21
~Message()22 Message::~Message() {
23 CloseHandles();
24 }
25
Initialize(size_t capacity,bool zero_initialized)26 void Message::Initialize(size_t capacity, bool zero_initialized) {
27 DCHECK(!buffer_);
28 buffer_.reset(new internal::MessageBuffer(capacity, zero_initialized));
29 }
30
InitializeFromMojoMessage(ScopedMessageHandle message,uint32_t num_bytes,std::vector<Handle> * handles)31 void Message::InitializeFromMojoMessage(ScopedMessageHandle message,
32 uint32_t num_bytes,
33 std::vector<Handle>* handles) {
34 DCHECK(!buffer_);
35 buffer_.reset(new internal::MessageBuffer(std::move(message), num_bytes));
36 handles_.swap(*handles);
37 }
38
MoveTo(Message * destination)39 void Message::MoveTo(Message* destination) {
40 DCHECK(this != destination);
41
42 // No copy needed.
43 std::swap(destination->buffer_, buffer_);
44 std::swap(destination->handles_, handles_);
45
46 CloseHandles();
47 handles_.clear();
48 buffer_.reset();
49 }
50
TakeMojoMessage()51 ScopedMessageHandle Message::TakeMojoMessage() {
52 if (handles_.empty()) // Fast path for the common case: No handles.
53 return buffer_->TakeMessage();
54
55 // Allocate a new message with space for the handles, then copy the buffer
56 // contents into it.
57 //
58 // TODO(rockot): We could avoid this copy by extending GetSerializedSize()
59 // behavior to collect handles. It's unoptimized for now because it's much
60 // more common to have messages with no handles.
61 ScopedMessageHandle new_message;
62 MojoResult rv = AllocMessage(
63 data_num_bytes(),
64 handles_.empty() ? nullptr
65 : reinterpret_cast<const MojoHandle*>(handles_.data()),
66 handles_.size(),
67 MOJO_ALLOC_MESSAGE_FLAG_NONE,
68 &new_message);
69 CHECK_EQ(rv, MOJO_RESULT_OK);
70 handles_.clear();
71
72 void* new_buffer = nullptr;
73 rv = GetMessageBuffer(new_message.get(), &new_buffer);
74 CHECK_EQ(rv, MOJO_RESULT_OK);
75
76 memcpy(new_buffer, data(), data_num_bytes());
77 buffer_.reset();
78
79 return new_message;
80 }
81
NotifyBadMessage(const std::string & error)82 void Message::NotifyBadMessage(const std::string& error) {
83 buffer_->NotifyBadMessage(error);
84 }
85
CloseHandles()86 void Message::CloseHandles() {
87 for (std::vector<Handle>::iterator it = handles_.begin();
88 it != handles_.end(); ++it) {
89 if (it->is_valid())
90 CloseRaw(*it);
91 }
92 }
93
ReadMessage(MessagePipeHandle handle,Message * message)94 MojoResult ReadMessage(MessagePipeHandle handle, Message* message) {
95 MojoResult rv;
96
97 std::vector<Handle> handles;
98 ScopedMessageHandle mojo_message;
99 uint32_t num_bytes = 0, num_handles = 0;
100 rv = ReadMessageNew(handle,
101 &mojo_message,
102 &num_bytes,
103 nullptr,
104 &num_handles,
105 MOJO_READ_MESSAGE_FLAG_NONE);
106 if (rv == MOJO_RESULT_RESOURCE_EXHAUSTED) {
107 DCHECK_GT(num_handles, 0u);
108 handles.resize(num_handles);
109 rv = ReadMessageNew(handle,
110 &mojo_message,
111 &num_bytes,
112 reinterpret_cast<MojoHandle*>(handles.data()),
113 &num_handles,
114 MOJO_READ_MESSAGE_FLAG_NONE);
115 }
116
117 if (rv != MOJO_RESULT_OK)
118 return rv;
119
120 message->InitializeFromMojoMessage(
121 std::move(mojo_message), num_bytes, &handles);
122 return MOJO_RESULT_OK;
123 }
124
125 } // namespace mojo
126