1 // Copyright (c) 2011 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 10 #include "base/synchronization/lock.h" 11 #include "ipc/ipc_channel_proxy.h" 12 13 // Base class used to allow synchronous IPC messages to be sent and 14 // received in an asynchronous manner. To use this class add it as a filter to 15 // your IPC channel using ChannelProxy::AddFilter(). From then on, before 16 // sending a synchronous message, call SyncMessageReplyDispatcher::Push() with 17 // a callback and a key. This class will then handle the message response and 18 // will call the callback when it is received. 19 // 20 // This class is intended to be extended by classes implementing 21 // HandleMessageType with delegation for the messages they expect to receive in 22 // cases where you care about the return values of synchronous messages. 23 // 24 // Sample usage pattern: 25 // Define a class which inherits from SyncMessageCallContext which specifies 26 // the output_type tuple and has a Completed member function. 27 // class SampleContext 28 // : public SyncMessageReplyDispatcher::SyncMessageCallContext { 29 // public: 30 // typedef Tuple1<int> output_type; 31 // void Completed(int arg) {} 32 // }; 33 // 34 // // Add handling for desired message types. 35 // class SyncMessageReplyDispatcherImpl : public SyncMessageReplyDispatcher { 36 // virtual bool HandleMessageType(const IPC::Message& msg, 37 // SyncMessageReplyDispatcher* context) { 38 // switch (context->message_type()) { 39 // case AutomationMsg_CreateExternalTab::ID: 40 // InvokeCallback<CreateExternalTabContext>(msg, context); 41 // break; 42 // [HANDLING FOR OTHER EXPECTED MESSAGE TYPES] 43 // } 44 // } 45 // 46 // // Add the filter 47 // IPC::SyncChannel channel_; 48 // channel_.AddFilter(new SyncMessageReplyDispatcherImpl()); 49 // 50 // sync_->Push(msg, new SampleContext, this); 51 // channel_->ChannelProxy::Send(msg); 52 // 53 class SyncMessageReplyDispatcher : public IPC::ChannelProxy::MessageFilter { 54 public: 55 class SyncMessageCallContext { 56 public: 57 SyncMessageCallContext() 58 : id_(0), 59 message_type_(0), 60 key_(NULL) {} 61 62 virtual ~SyncMessageCallContext() {} 63 64 uint32 message_type() const { 65 return message_type_; 66 } 67 68 private: 69 int id_; 70 uint32 message_type_; 71 void* key_; 72 73 friend class SyncMessageReplyDispatcher; 74 }; 75 76 SyncMessageReplyDispatcher() {} 77 void Push(IPC::SyncMessage* msg, SyncMessageCallContext* context, 78 void* key); 79 void Cancel(void* key); 80 81 protected: 82 typedef std::deque<SyncMessageCallContext*> PendingSyncMessageQueue; 83 84 SyncMessageCallContext* GetContext(const IPC::Message& msg); 85 86 virtual bool OnMessageReceived(const IPC::Message& msg); 87 88 // Child classes must implement a handler for the message types they are 89 // interested in handling responses for. If you don't care about the replies 90 // to any of the sync messages you are handling, then you don't have to 91 // implement this. 92 virtual bool HandleMessageType(const IPC::Message& msg, 93 SyncMessageCallContext* context); 94 95 template <typename T> 96 void InvokeCallback(const IPC::Message& msg, 97 SyncMessageCallContext* call_context) { 98 if (!call_context || !call_context->key_) { 99 NOTREACHED() << "Invalid context parameter"; 100 return; 101 } 102 103 T* context = static_cast<T*>(call_context); 104 T::output_type tmp; // Acts as "initializer" for output parameters. 105 IPC::ParamDeserializer<T::output_type> deserializer(tmp); 106 if (deserializer.MessageReplyDeserializer::SerializeOutputParameters(msg)) { 107 DispatchToMethod(context, &T::Completed, deserializer.out_); 108 delete context; 109 } else { 110 // TODO(stoyan): How to handle errors? 111 } 112 } 113 114 PendingSyncMessageQueue message_queue_; 115 base::Lock message_queue_lock_; 116 }; 117 118 #endif // CHROME_FRAME_SYNC_MSG_REPLY_DISPATCHER_H_ 119