OLD | NEW |
(Empty) | |
| 1 // 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 #include <stdio.h> |
| 6 #include <iostream> |
| 7 #include <string> |
| 8 #include <sstream> |
| 9 |
| 10 #include "base/message_loop.h" |
| 11 #include "base/platform_thread.h" |
| 12 #include "base/process_util.h" |
| 13 #include "base/sync_socket.h" |
| 14 #include "ipc/ipc_channel.h" |
| 15 #include "ipc/ipc_channel_proxy.h" |
| 16 #include "ipc/ipc_message_utils.h" |
| 17 #include "ipc/ipc_tests.h" |
| 18 #include "testing/gtest/include/gtest/gtest.h" |
| 19 #include "testing/multiprocess_func_list.h" |
| 20 |
| 21 |
| 22 // We don't actually use the messages defined in this file, but we do this |
| 23 // to get to the IPC macros. |
| 24 #define MESSAGES_INTERNAL_FILE "ipc/ipc_sync_message_unittest.h" |
| 25 #include "ipc/ipc_message_macros.h" |
| 26 |
| 27 enum IPCMessageIds { |
| 28 UNUSED_IPC_TYPE, |
| 29 SERVER_FIRST_IPC_TYPE, // SetHandle message sent to server. |
| 30 SERVER_SECOND_IPC_TYPE, // Shutdown message sent to server. |
| 31 CLIENT_FIRST_IPC_TYPE // Response message sent to client. |
| 32 }; |
| 33 |
| 34 namespace { |
| 35 const char kHelloString[] = "Hello, SyncSocket Client"; |
| 36 const size_t kHelloStringLength = arraysize(kHelloString); |
| 37 } // namespace |
| 38 |
| 39 // Message class to pass a HANDLE to another process. |
| 40 class MsgClassSetHandle |
| 41 : public IPC::MessageWithTuple< Tuple1<base::SyncSocket::Handle> > { |
| 42 public: |
| 43 enum { ID = SERVER_FIRST_IPC_TYPE }; |
| 44 explicit MsgClassSetHandle(const base::SyncSocket::Handle arg1) |
| 45 : IPC::MessageWithTuple< Tuple1<base::SyncSocket::Handle> >( |
| 46 MSG_ROUTING_CONTROL, ID, MakeRefTuple(arg1)) {} |
| 47 |
| 48 private: |
| 49 DISALLOW_COPY_AND_ASSIGN(MsgClassSetHandle); |
| 50 }; |
| 51 |
| 52 // Message class to pass a response to the server. |
| 53 class MsgClassResponse |
| 54 : public IPC::MessageWithTuple< Tuple1<std::string> > { |
| 55 public: |
| 56 enum { ID = CLIENT_FIRST_IPC_TYPE }; |
| 57 explicit MsgClassResponse(const std::string& arg1) |
| 58 : IPC::MessageWithTuple< Tuple1<std::string> >( |
| 59 MSG_ROUTING_CONTROL, ID, MakeRefTuple(arg1)) {} |
| 60 |
| 61 private: |
| 62 DISALLOW_COPY_AND_ASSIGN(MsgClassResponse); |
| 63 }; |
| 64 |
| 65 // Message class to tell the server to shut down. |
| 66 class MsgClassShutdown |
| 67 : public IPC::MessageWithTuple< Tuple0 > { |
| 68 public: |
| 69 enum { ID = SERVER_SECOND_IPC_TYPE }; |
| 70 MsgClassShutdown() |
| 71 : IPC::MessageWithTuple< Tuple0 >( |
| 72 MSG_ROUTING_CONTROL, ID, MakeTuple()) {} |
| 73 |
| 74 private: |
| 75 DISALLOW_COPY_AND_ASSIGN(MsgClassShutdown); |
| 76 }; |
| 77 |
| 78 // The SyncSocket server listener class processes two sorts of |
| 79 // messages from the client. |
| 80 class SyncSocketServerListener : public IPC::Channel::Listener { |
| 81 public: |
| 82 SyncSocketServerListener() : chan_(NULL) { |
| 83 } |
| 84 |
| 85 void Init(IPC::Channel* chan) { |
| 86 chan_ = chan; |
| 87 } |
| 88 |
| 89 virtual void OnMessageReceived(const IPC::Message& msg) { |
| 90 if (msg.routing_id() == MSG_ROUTING_CONTROL) { |
| 91 IPC_BEGIN_MESSAGE_MAP(SyncSocketServerListener, msg) |
| 92 IPC_MESSAGE_HANDLER(MsgClassSetHandle, OnMsgClassSetHandle) |
| 93 IPC_MESSAGE_HANDLER(MsgClassShutdown, OnMsgClassShutdown) |
| 94 IPC_END_MESSAGE_MAP() |
| 95 } |
| 96 } |
| 97 |
| 98 private: |
| 99 // This sort of message is sent first, causing the transfer of |
| 100 // the handle for the SyncSocket. This message sends a buffer |
| 101 // on the SyncSocket and then sends a response to the client. |
| 102 void OnMsgClassSetHandle(const base::SyncSocket::Handle handle) { |
| 103 base::SyncSocket sync_socket(handle); |
| 104 EXPECT_EQ(sync_socket.Send(static_cast<const void*>(kHelloString), |
| 105 kHelloStringLength), kHelloStringLength); |
| 106 IPC::Message* msg = new MsgClassResponse(kHelloString); |
| 107 EXPECT_NE(msg, reinterpret_cast<IPC::Message*>(NULL)); |
| 108 EXPECT_TRUE(chan_->Send(msg)); |
| 109 } |
| 110 |
| 111 // When the client responds, it sends back a shutdown message, |
| 112 // which causes the message loop to exit. |
| 113 void OnMsgClassShutdown() { |
| 114 MessageLoop::current()->Quit(); |
| 115 } |
| 116 |
| 117 IPC::Channel* chan_; |
| 118 |
| 119 DISALLOW_COPY_AND_ASSIGN(SyncSocketServerListener); |
| 120 }; |
| 121 |
| 122 // Runs the fuzzing server child mode. Returns when the preset number |
| 123 // of messages have been received. |
| 124 MULTIPROCESS_TEST_MAIN(RunSyncSocketServer) { |
| 125 MessageLoopForIO main_message_loop; |
| 126 SyncSocketServerListener listener; |
| 127 IPC::Channel chan(kSyncSocketChannel, IPC::Channel::MODE_CLIENT, &listener); |
| 128 EXPECT_TRUE(chan.Connect()); |
| 129 listener.Init(&chan); |
| 130 MessageLoop::current()->Run(); |
| 131 return 0; |
| 132 } |
| 133 |
| 134 // The SyncSocket client listener only processes one sort of message, |
| 135 // a response from the server. |
| 136 class SyncSocketClientListener : public IPC::Channel::Listener { |
| 137 public: |
| 138 SyncSocketClientListener() { |
| 139 } |
| 140 |
| 141 void Init(base::SyncSocket* socket, IPC::Channel* chan) { |
| 142 socket_ = socket; |
| 143 chan_ = chan; |
| 144 } |
| 145 |
| 146 virtual void OnMessageReceived(const IPC::Message& msg) { |
| 147 if (msg.routing_id() == MSG_ROUTING_CONTROL) { |
| 148 IPC_BEGIN_MESSAGE_MAP(SyncSocketClientListener, msg) |
| 149 IPC_MESSAGE_HANDLER(MsgClassResponse, OnMsgClassResponse) |
| 150 IPC_END_MESSAGE_MAP() |
| 151 } |
| 152 } |
| 153 |
| 154 private: |
| 155 // When a response is received from the server, it sends the same |
| 156 // string as was written on the SyncSocket. These are compared |
| 157 // and a shutdown message is sent back to the server. |
| 158 void OnMsgClassResponse(const std::string& str) { |
| 159 char buf[kHelloStringLength]; |
| 160 socket_->Receive(static_cast<void*>(buf), kHelloStringLength); |
| 161 EXPECT_EQ(strcmp(str.c_str(), buf), 0); |
| 162 IPC::Message* msg = new MsgClassShutdown(); |
| 163 EXPECT_NE(msg, reinterpret_cast<IPC::Message*>(NULL)); |
| 164 EXPECT_TRUE(chan_->Send(msg)); |
| 165 MessageLoop::current()->Quit(); |
| 166 } |
| 167 |
| 168 base::SyncSocket* socket_; |
| 169 IPC::Channel* chan_; |
| 170 |
| 171 DISALLOW_COPY_AND_ASSIGN(SyncSocketClientListener); |
| 172 }; |
| 173 |
| 174 class SyncSocketTest : public IPCChannelTest { |
| 175 }; |
| 176 |
| 177 TEST_F(SyncSocketTest, SanityTest) { |
| 178 SyncSocketClientListener listener; |
| 179 IPC::Channel chan(kSyncSocketChannel, IPC::Channel::MODE_SERVER, |
| 180 &listener); |
| 181 base::ProcessHandle server_process = SpawnChild(SYNC_SOCKET_SERVER, &chan); |
| 182 ASSERT_TRUE(server_process); |
| 183 // Create a pair of SyncSockets. |
| 184 base::SyncSocket* pair[2]; |
| 185 base::SyncSocket::CreatePair(pair); |
| 186 base::SyncSocket::Handle target_handle; |
| 187 #if defined(OS_WIN) |
| 188 // On windows we need to duplicate the handle into the server process. |
| 189 BOOL retval = DuplicateHandle(GetCurrentProcess(), pair[1]->handle(), |
| 190 server_process, &target_handle, |
| 191 0, FALSE, DUPLICATE_SAME_ACCESS); |
| 192 EXPECT_TRUE(retval); |
| 193 #else |
| 194 target_handle = pair[1]->handle(); |
| 195 #endif // defined(OS_WIN) |
| 196 // Connect the channel and listener. |
| 197 ASSERT_TRUE(chan.Connect()); |
| 198 listener.Init(pair[0], &chan); |
| 199 // Set up a message to pass the handle to the server. |
| 200 IPC::Message* msg = new MsgClassSetHandle(target_handle); |
| 201 EXPECT_NE(msg, reinterpret_cast<IPC::Message*>(NULL)); |
| 202 EXPECT_TRUE(chan.Send(msg)); |
| 203 // Use the current thread as the I/O thread. |
| 204 MessageLoop::current()->Run(); |
| 205 // Shut down. |
| 206 delete pair[0]; |
| 207 delete pair[1]; |
| 208 EXPECT_TRUE(base::WaitForSingleProcess(server_process, 5000)); |
| 209 base::CloseProcessHandle(server_process); |
| 210 } |
| 211 |
OLD | NEW |