Chromium Code Reviews| 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..8a010a2aab635ae2d1d44fc71bce9352984ddd28 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,147 @@ 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) { } |
| + |
| + private: |
| + bool OnMessageReceived(const Message& message) { |
| + IPC_BEGIN_MESSAGE_MAP(RestrictedDispatchServer, message) |
| + IPC_MESSAGE_HANDLER(SyncChannelTestMsg_PostPing, OnPostPing) |
| + IPC_MESSAGE_HANDLER(SyncChannelTestMsg_NoArgs, OnNoArgs) |
| + IPC_MESSAGE_HANDLER(SyncChannelTestMsg_Done, Done) |
| + IPC_END_MESSAGE_MAP() |
| + return true; |
| + } |
| + |
| + void OnPostPing(int ping) { |
| + MessageLoop::current()->PostTask(FROM_HERE, |
| + NewRunnableMethod(this, &RestrictedDispatchServer::OnDoPing, ping)); |
| + } |
| + |
| + 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)); |
| + } |
| + |
| + 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, int* success) |
| + : Worker("restricted_channel", Channel::MODE_CLIENT), |
| + ping_(0), |
| + 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); |
| + |
| + Send(new SyncChannelTestMsg_PostPing(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())); |
| + |
| + Send(new SyncChannelTestMsg_PostPing(2)); |
|
piman
2011/04/08 02:07:03
This is flaky... even though I post a task on the
|
| + 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_; |
| + int* success_; |
| + WaitableEvent* sent_ping_event_; |
| +}; |
| +} // namespace |
| + |
| +TEST_F(IPCSyncChannelTest, RestrictedDispatch) { |
| + WaitableEvent sent_ping_event(false, false); |
| + |
| + int success = 0; |
| + std::vector<Worker*> workers; |
| + workers.push_back(new NonRestrictedDispatchServer); |
| + workers.push_back(new RestrictedDispatchServer(&sent_ping_event)); |
| + workers.push_back(new RestrictedDispatchClient(&sent_ping_event, &success)); |
| + RunTest(workers); |
| + EXPECT_EQ(3, success); |
| +} |