Index: ipc/ipc_sync_channel_unittest.cc |
diff --git a/ipc/ipc_sync_channel_unittest.cc b/ipc/ipc_sync_channel_unittest.cc |
index 8e207bf6affb2a0c0ae7a9d60d15dc72f5366c78..6952aac419173fdc5db6fb687d74fac7720033ce 100644 |
--- a/ipc/ipc_sync_channel_unittest.cc |
+++ b/ipc/ipc_sync_channel_unittest.cc |
@@ -158,6 +158,8 @@ class Worker : public Channel::Listener, public Message::Sender { |
return overrided_thread_ ? overrided_thread_ : &listener_thread_; |
} |
+ const base::Thread& ipc_thread() const { return ipc_thread_; } |
+ |
private: |
// Called on the listener thread to create the sync channel. |
void OnStart() { |
@@ -1164,4 +1166,152 @@ TEST_F(IPCSyncChannelTest, SendAfterClose) { |
EXPECT_FALSE(server.send_result()); |
} |
+//----------------------------------------------------------------------------- |
+ |
+namespace { |
+ |
+class RestrictedDispatchServer : public Worker { |
+ public: |
+ RestrictedDispatchServer(WaitableEvent* sent_ping_event) |
+ : Worker("restricted_channel", Channel::MODE_SERVER), |
+ sent_ping_event_(sent_ping_event) { } |
+ |
+ void OnDoPing(int ping) { |
+ // Send an asynchronous message that unblocks the caller. |
+ IPC::Message* msg = new SyncChannelTestMsg_Ping(ping); |
+ msg->set_unblock(true); |
+ Send(msg); |
+ // Signal the event after the message has been sent on the channel, on the |
+ // IPC thread. |
+ ipc_thread().message_loop()->PostTask(FROM_HERE, |
+ NewRunnableMethod(this, &RestrictedDispatchServer::OnPingSent)); |
+ } |
+ |
+ base::Thread* ListenerThread() { return Worker::ListenerThread(); } |
+ |
+ private: |
+ bool OnMessageReceived(const Message& message) { |
+ IPC_BEGIN_MESSAGE_MAP(RestrictedDispatchServer, message) |
+ IPC_MESSAGE_HANDLER(SyncChannelTestMsg_NoArgs, OnNoArgs) |
+ IPC_MESSAGE_HANDLER(SyncChannelTestMsg_Done, Done) |
+ IPC_END_MESSAGE_MAP() |
+ return true; |
+ } |
+ |
+ void OnPingSent() { |
+ sent_ping_event_->Signal(); |
+ } |
+ |
+ void OnNoArgs() { } |
+ WaitableEvent* sent_ping_event_; |
+}; |
+ |
+class NonRestrictedDispatchServer : public Worker { |
+ public: |
+ NonRestrictedDispatchServer() |
+ : Worker("non_restricted_channel", Channel::MODE_SERVER) {} |
+ |
+ private: |
+ bool OnMessageReceived(const Message& message) { |
+ IPC_BEGIN_MESSAGE_MAP(NonRestrictedDispatchServer, message) |
+ IPC_MESSAGE_HANDLER(SyncChannelTestMsg_NoArgs, OnNoArgs) |
+ IPC_MESSAGE_HANDLER(SyncChannelTestMsg_Done, Done) |
+ IPC_END_MESSAGE_MAP() |
+ return true; |
+ } |
+ void OnNoArgs() { } |
+}; |
+ |
+class RestrictedDispatchClient : public Worker { |
+ public: |
+ RestrictedDispatchClient(WaitableEvent* sent_ping_event, |
+ RestrictedDispatchServer* server, |
+ int* success) |
+ : Worker("restricted_channel", Channel::MODE_CLIENT), |
+ ping_(0), |
+ server_(server), |
+ success_(success), |
+ sent_ping_event_(sent_ping_event) {} |
+ |
+ void Run() { |
+ // Incoming messages from our channel should only be dispatched when we |
+ // send a message on that same channel. |
+ channel()->SetRestrictDispatchToSameChannel(true); |
+ |
+ server_->ListenerThread()->message_loop()->PostTask(FROM_HERE, |
+ NewRunnableMethod(server_, &RestrictedDispatchServer::OnDoPing, 1)); |
+ sent_ping_event_->Wait(); |
+ Send(new SyncChannelTestMsg_NoArgs); |
+ if (ping_ == 1) |
+ ++*success_; |
+ else |
+ LOG(ERROR) << "Send failed to dispatch incoming message on same channel"; |
+ |
+ scoped_ptr<SyncChannel> non_restricted_channel(new SyncChannel( |
+ "non_restricted_channel", Channel::MODE_CLIENT, this, |
+ ipc_thread().message_loop(), true, shutdown_event())); |
+ |
+ server_->ListenerThread()->message_loop()->PostTask(FROM_HERE, |
+ NewRunnableMethod(server_, &RestrictedDispatchServer::OnDoPing, 2)); |
+ sent_ping_event_->Wait(); |
+ // Check that the incoming message is *not* dispatched when sending on the |
+ // non restricted channel. |
+ // TODO(piman): there is a possibility of a false positive race condition |
+ // here, if the message that was posted on the server-side end of the pipe |
+ // is not visible yet on the client side, but I don't know how to solve this |
+ // without hooking into the internals of SyncChannel. I haven't seen it in |
+ // practice (i.e. not setting SetRestrictDispatchToSameChannel does cause |
+ // the following to fail). |
+ non_restricted_channel->Send(new SyncChannelTestMsg_NoArgs); |
+ if (ping_ == 1) |
+ ++*success_; |
+ else |
+ LOG(ERROR) << "Send dispatched message from restricted channel"; |
+ |
+ Send(new SyncChannelTestMsg_NoArgs); |
+ if (ping_ == 2) |
+ ++*success_; |
+ else |
+ LOG(ERROR) << "Send failed to dispatch incoming message on same channel"; |
+ |
+ non_restricted_channel->Send(new SyncChannelTestMsg_Done); |
+ non_restricted_channel.reset(); |
+ Send(new SyncChannelTestMsg_Done); |
+ Done(); |
+ } |
+ |
+ private: |
+ bool OnMessageReceived(const Message& message) { |
+ IPC_BEGIN_MESSAGE_MAP(RestrictedDispatchClient, message) |
+ IPC_MESSAGE_HANDLER(SyncChannelTestMsg_Ping, OnPing) |
+ IPC_END_MESSAGE_MAP() |
+ return true; |
+ } |
+ |
+ void OnPing(int ping) { |
+ ping_ = ping; |
+ } |
+ |
+ int ping_; |
+ RestrictedDispatchServer* server_; |
+ int* success_; |
+ WaitableEvent* sent_ping_event_; |
+}; |
+ |
+} // namespace |
+ |
+TEST_F(IPCSyncChannelTest, RestrictedDispatch) { |
+ WaitableEvent sent_ping_event(false, false); |
+ |
+ RestrictedDispatchServer* server = |
+ new RestrictedDispatchServer(&sent_ping_event); |
+ int success = 0; |
+ std::vector<Worker*> workers; |
+ workers.push_back(new NonRestrictedDispatchServer); |
+ workers.push_back(server); |
+ workers.push_back( |
+ new RestrictedDispatchClient(&sent_ping_event, server, &success)); |
+ RunTest(workers); |
+ EXPECT_EQ(3, success); |
+} |