1// Copyright (c) 2012 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 "build/build_config.h"
6
7#if defined(OS_WIN)
8#include <windows.h>
9#endif
10#include <stack>
11
12#include "base/atomic_sequence_num.h"
13#include "base/lazy_instance.h"
14#include "base/logging.h"
15#include "base/synchronization/waitable_event.h"
16#include "ipc/ipc_sync_message.h"
17
18namespace {
19
20struct WaitableEventLazyInstanceTraits
21    : public base::DefaultLazyInstanceTraits<base::WaitableEvent> {
22  static base::WaitableEvent* New(void* instance) {
23    // Use placement new to initialize our instance in our preallocated space.
24    return new (instance) base::WaitableEvent(true, true);
25  }
26};
27
28base::LazyInstance<base::WaitableEvent, WaitableEventLazyInstanceTraits>
29    dummy_event = LAZY_INSTANCE_INITIALIZER;
30
31base::StaticAtomicSequenceNumber g_next_id;
32
33}  // namespace
34
35namespace IPC {
36
37#define kSyncMessageHeaderSize 4
38
39SyncMessage::SyncMessage(
40    int32 routing_id,
41    uint32 type,
42    PriorityValue priority,
43    MessageReplyDeserializer* deserializer)
44    : Message(routing_id, type, priority),
45      deserializer_(deserializer),
46      pump_messages_event_(NULL)
47      {
48  set_sync();
49  set_unblock(true);
50
51  // Add synchronous message data before the message payload.
52  SyncHeader header;
53  header.message_id = g_next_id.GetNext();
54  WriteSyncHeader(this, header);
55}
56
57SyncMessage::~SyncMessage() {
58}
59
60MessageReplyDeserializer* SyncMessage::GetReplyDeserializer() {
61  DCHECK(deserializer_.get());
62  return deserializer_.release();
63}
64
65void SyncMessage::EnableMessagePumping() {
66  DCHECK(!pump_messages_event_);
67  set_pump_messages_event(dummy_event.Pointer());
68}
69
70bool SyncMessage::IsMessageReplyTo(const Message& msg, int request_id) {
71  if (!msg.is_reply())
72    return false;
73
74  return GetMessageId(msg) == request_id;
75}
76
77PickleIterator SyncMessage::GetDataIterator(const Message* msg) {
78  PickleIterator iter(*msg);
79  if (!iter.SkipBytes(kSyncMessageHeaderSize))
80    return PickleIterator();
81  else
82    return iter;
83}
84
85int SyncMessage::GetMessageId(const Message& msg) {
86  if (!msg.is_sync() && !msg.is_reply())
87    return 0;
88
89  SyncHeader header;
90  if (!ReadSyncHeader(msg, &header))
91    return 0;
92
93  return header.message_id;
94}
95
96Message* SyncMessage::GenerateReply(const Message* msg) {
97  DCHECK(msg->is_sync());
98
99  Message* reply = new Message(msg->routing_id(), IPC_REPLY_ID,
100                               msg->priority());
101  reply->set_reply();
102
103  SyncHeader header;
104
105  // use the same message id, but this time reply bit is set
106  header.message_id = GetMessageId(*msg);
107  WriteSyncHeader(reply, header);
108
109  return reply;
110}
111
112bool SyncMessage::ReadSyncHeader(const Message& msg, SyncHeader* header) {
113  DCHECK(msg.is_sync() || msg.is_reply());
114
115  PickleIterator iter(msg);
116  bool result = msg.ReadInt(&iter, &header->message_id);
117  if (!result) {
118    NOTREACHED();
119    return false;
120  }
121
122  return true;
123}
124
125bool SyncMessage::WriteSyncHeader(Message* msg, const SyncHeader& header) {
126  DCHECK(msg->is_sync() || msg->is_reply());
127  DCHECK(msg->payload_size() == 0);
128  bool result = msg->WriteInt(header.message_id);
129  if (!result) {
130    NOTREACHED();
131    return false;
132  }
133
134  // Note: if you add anything here, you need to update kSyncMessageHeaderSize.
135  DCHECK(kSyncMessageHeaderSize == msg->payload_size());
136
137  return true;
138}
139
140
141bool MessageReplyDeserializer::SerializeOutputParameters(const Message& msg) {
142  return SerializeOutputParameters(msg, SyncMessage::GetDataIterator(&msg));
143}
144
145}  // namespace IPC
146