1 // Copyright 2012 The Chromium Authors
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 "ipc/ipc_sync_message.h"
6
7 #include <stdint.h>
8
9 #include "base/atomic_sequence_num.h"
10 #include "base/check.h"
11 #include "base/notreached.h"
12 #include "base/synchronization/waitable_event.h"
13 #include "build/build_config.h"
14
15 namespace {
16
17 base::AtomicSequenceNumber g_next_id;
18
19 } // namespace
20
21 namespace IPC {
22
23 #define kSyncMessageHeaderSize 4
24
SyncMessage(int32_t routing_id,uint32_t type,PriorityValue priority,std::unique_ptr<MessageReplyDeserializer> deserializer)25 SyncMessage::SyncMessage(int32_t routing_id,
26 uint32_t type,
27 PriorityValue priority,
28 std::unique_ptr<MessageReplyDeserializer> deserializer)
29 : Message(routing_id, type, priority),
30 deserializer_(std::move(deserializer)) {
31 set_sync();
32 set_unblock(true);
33
34 // Add synchronous message data before the message payload.
35 SyncHeader header;
36 header.message_id = g_next_id.GetNext();
37 WriteSyncHeader(this, header);
38 }
39
40 SyncMessage::~SyncMessage() = default;
41
TakeReplyDeserializer()42 std::unique_ptr<MessageReplyDeserializer> SyncMessage::TakeReplyDeserializer() {
43 DCHECK(deserializer_);
44 return std::move(deserializer_);
45 }
46
IsMessageReplyTo(const Message & msg,int request_id)47 bool SyncMessage::IsMessageReplyTo(const Message& msg, int request_id) {
48 if (!msg.is_reply())
49 return false;
50
51 return GetMessageId(msg) == request_id;
52 }
53
GetDataIterator(const Message * msg)54 base::PickleIterator SyncMessage::GetDataIterator(const Message* msg) {
55 base::PickleIterator iter(*msg);
56 if (!iter.SkipBytes(kSyncMessageHeaderSize))
57 return base::PickleIterator();
58 else
59 return iter;
60 }
61
GetMessageId(const Message & msg)62 int SyncMessage::GetMessageId(const Message& msg) {
63 if (!msg.is_sync() && !msg.is_reply())
64 return 0;
65
66 SyncHeader header;
67 if (!ReadSyncHeader(msg, &header))
68 return 0;
69
70 return header.message_id;
71 }
72
GenerateReply(const Message * msg)73 Message* SyncMessage::GenerateReply(const Message* msg) {
74 DCHECK(msg->is_sync());
75
76 Message* reply = new Message(msg->routing_id(), IPC_REPLY_ID,
77 msg->priority());
78 reply->set_reply();
79
80 SyncHeader header;
81
82 // use the same message id, but this time reply bit is set
83 header.message_id = GetMessageId(*msg);
84 WriteSyncHeader(reply, header);
85
86 return reply;
87 }
88
ReadSyncHeader(const Message & msg,SyncHeader * header)89 bool SyncMessage::ReadSyncHeader(const Message& msg, SyncHeader* header) {
90 DCHECK(msg.is_sync() || msg.is_reply());
91
92 base::PickleIterator iter(msg);
93 bool result = iter.ReadInt(&header->message_id);
94 if (!result) {
95 NOTREACHED();
96 return false;
97 }
98
99 return true;
100 }
101
WriteSyncHeader(Message * msg,const SyncHeader & header)102 bool SyncMessage::WriteSyncHeader(Message* msg, const SyncHeader& header) {
103 DCHECK(msg->is_sync() || msg->is_reply());
104 DCHECK(msg->payload_size() == 0);
105 msg->WriteInt(header.message_id);
106
107 // Note: if you add anything here, you need to update kSyncMessageHeaderSize.
108 DCHECK(kSyncMessageHeaderSize == msg->payload_size());
109
110 return true;
111 }
112
113
SerializeOutputParameters(const Message & msg)114 bool MessageReplyDeserializer::SerializeOutputParameters(const Message& msg) {
115 return SerializeOutputParameters(msg, SyncMessage::GetDataIterator(&msg));
116 }
117
PendingSyncMsg(int id,std::unique_ptr<MessageReplyDeserializer> d,std::unique_ptr<base::WaitableEvent> e)118 PendingSyncMsg::PendingSyncMsg(int id,
119 std::unique_ptr<MessageReplyDeserializer> d,
120 std::unique_ptr<base::WaitableEvent> e)
121 : id(id), deserializer(std::move(d)), done_event(std::move(e)) {}
122
123 PendingSyncMsg::PendingSyncMsg(PendingSyncMsg&& that) = default;
124
125 PendingSyncMsg::~PendingSyncMsg() = default;
126
127 } // namespace IPC
128