blob: a1687886bb80ac853547f9270bec358aa8d6f2b5 [file] [log] [blame]
[email protected]f7817822009-09-24 05:11:581// Copyright (c) 2009 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#ifndef CHROME_FRAME_SYNC_MSG_REPLY_DISPATCHER_H_
6#define CHROME_FRAME_SYNC_MSG_REPLY_DISPATCHER_H_
7
8#include <deque>
9
[email protected]2041cf342010-02-19 03:15:5910#include "base/callback.h"
[email protected]20305ec2011-01-21 04:55:5211#include "base/synchronization/lock.h"
[email protected]f7817822009-09-24 05:11:5812#include "ipc/ipc_channel_proxy.h"
13
14// Base class used to allow synchronous IPC messages to be sent and
15// received in an asynchronous manner. To use this class add it as a filter to
16// your IPC channel using ChannelProxy::AddFilter(). From then on, before
17// sending a synchronous message, call SyncMessageReplyDispatcher::Push() with
18// a callback and a key. This class will then handle the message response and
19// will call the callback when it is received.
20//
21// This class is intended to be extended by classes implementing
22// HandleMessageType with delegation for the messages they expect to receive in
23// cases where you care about the return values of synchronous messages.
24//
25// Sample usage pattern:
[email protected]d0b8e5f2010-05-18 04:26:0226// Define a class which inherits from SyncMessageCallContext which specifies
27// the output_type tuple and has a Completed member function.
28// class SampleContext
29// : public SyncMessageReplyDispatcher::SyncMessageCallContext {
30// public:
31// typedef Tuple1<int> output_type;
32// void Completed(int arg) {}
33// };
[email protected]f7817822009-09-24 05:11:5834//
35// // Add handling for desired message types.
36// class SyncMessageReplyDispatcherImpl : public SyncMessageReplyDispatcher {
37// virtual bool HandleMessageType(const IPC::Message& msg,
[email protected]d0b8e5f2010-05-18 04:26:0238// SyncMessageReplyDispatcher* context) {
39// switch (context->message_type()) {
[email protected]f7817822009-09-24 05:11:5840// case AutomationMsg_CreateExternalTab::ID:
[email protected]d0b8e5f2010-05-18 04:26:0241// InvokeCallback<CreateExternalTabContext>(msg, context);
[email protected]f7817822009-09-24 05:11:5842// break;
43// [HANDLING FOR OTHER EXPECTED MESSAGE TYPES]
44// }
45// }
46//
47// // Add the filter
48// IPC::SyncChannel channel_;
49// channel_.AddFilter(new SyncMessageReplyDispatcherImpl());
50//
[email protected]d0b8e5f2010-05-18 04:26:0251// sync_->Push(msg, new SampleContext, this);
[email protected]f7817822009-09-24 05:11:5852// channel_->ChannelProxy::Send(msg);
53//
54class SyncMessageReplyDispatcher : public IPC::ChannelProxy::MessageFilter {
55 public:
[email protected]d0b8e5f2010-05-18 04:26:0256 class SyncMessageCallContext {
57 public:
58 SyncMessageCallContext()
59 : id_(0),
60 message_type_(0),
61 key_(NULL) {}
62
63 virtual ~SyncMessageCallContext() {}
64
65 uint32 message_type() const {
66 return message_type_;
67 }
68
69 private:
70 int id_;
71 uint32 message_type_;
72 void* key_;
73
74 friend class SyncMessageReplyDispatcher;
75 };
76
[email protected]f7817822009-09-24 05:11:5877 SyncMessageReplyDispatcher() {}
[email protected]d0b8e5f2010-05-18 04:26:0278 void Push(IPC::SyncMessage* msg, SyncMessageCallContext* context,
79 void* key);
[email protected]f7817822009-09-24 05:11:5880 void Cancel(void* key);
81
82 protected:
[email protected]d0b8e5f2010-05-18 04:26:0283 typedef std::deque<SyncMessageCallContext*> PendingSyncMessageQueue;
[email protected]f7817822009-09-24 05:11:5884
[email protected]d0b8e5f2010-05-18 04:26:0285 SyncMessageCallContext* GetContext(const IPC::Message& msg);
[email protected]f7817822009-09-24 05:11:5886
[email protected]f7817822009-09-24 05:11:5887 virtual bool OnMessageReceived(const IPC::Message& msg);
88
89 // Child classes must implement a handler for the message types they are
90 // interested in handling responses for. If you don't care about the replies
91 // to any of the sync messages you are handling, then you don't have to
92 // implement this.
93 virtual bool HandleMessageType(const IPC::Message& msg,
[email protected]d0b8e5f2010-05-18 04:26:0294 SyncMessageCallContext* context);
[email protected]f7817822009-09-24 05:11:5895
96 template <typename T>
[email protected]d0b8e5f2010-05-18 04:26:0297 void InvokeCallback(const IPC::Message& msg,
98 SyncMessageCallContext* call_context) {
99 if (!call_context || !call_context->key_) {
100 NOTREACHED() << "Invalid context parameter";
[email protected]f7817822009-09-24 05:11:58101 return;
102 }
103
[email protected]d0b8e5f2010-05-18 04:26:02104 T* context = static_cast<T*>(call_context);
105 T::output_type tmp; // Acts as "initializer" for output parameters.
106 IPC::ParamDeserializer<T::output_type> deserializer(tmp);
[email protected]f7817822009-09-24 05:11:58107 if (deserializer.MessageReplyDeserializer::SerializeOutputParameters(msg)) {
[email protected]d0b8e5f2010-05-18 04:26:02108 DispatchToMethod(context, &T::Completed, deserializer.out_);
109 delete context;
[email protected]f7817822009-09-24 05:11:58110 } else {
111 // TODO(stoyan): How to handle errors?
112 }
113 }
114
115 PendingSyncMessageQueue message_queue_;
[email protected]20305ec2011-01-21 04:55:52116 base::Lock message_queue_lock_;
[email protected]f7817822009-09-24 05:11:58117};
118
119#endif // CHROME_FRAME_SYNC_MSG_REPLY_DISPATCHER_H_