brettw@google.com | 7c5cc67 | 2011-01-01 11:17:08 +0900 | [diff] [blame] | 1 | // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
sehr@google.com | 4f325aa | 2009-11-25 01:14:53 +0900 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
dmaclach@chromium.org | c1d3d42 | 2010-12-20 15:59:23 +0900 | [diff] [blame] | 5 | #include "base/sync_socket.h" |
| 6 | |
sehr@google.com | 4f325aa | 2009-11-25 01:14:53 +0900 | [diff] [blame] | 7 | #include <stdio.h> |
sehr@google.com | 4f325aa | 2009-11-25 01:14:53 +0900 | [diff] [blame] | 8 | #include <string> |
| 9 | #include <sstream> |
| 10 | |
| 11 | #include "base/message_loop.h" |
sehr@google.com | 4f325aa | 2009-11-25 01:14:53 +0900 | [diff] [blame] | 12 | #include "base/process_util.h" |
brettw@google.com | 7c5cc67 | 2011-01-01 11:17:08 +0900 | [diff] [blame] | 13 | #include "build/build_config.h" |
sehr@google.com | 4f325aa | 2009-11-25 01:14:53 +0900 | [diff] [blame] | 14 | #include "ipc/ipc_channel.h" |
| 15 | #include "ipc/ipc_channel_proxy.h" |
brettw@google.com | 7c5cc67 | 2011-01-01 11:17:08 +0900 | [diff] [blame] | 16 | #include "ipc/ipc_message_macros.h" |
sehr@google.com | 4f325aa | 2009-11-25 01:14:53 +0900 | [diff] [blame] | 17 | #include "ipc/ipc_message_utils.h" |
erg@google.com | e6ffcb5 | 2010-08-18 03:38:24 +0900 | [diff] [blame] | 18 | #include "ipc/ipc_message_utils_impl.h" |
sehr@google.com | 4f325aa | 2009-11-25 01:14:53 +0900 | [diff] [blame] | 19 | #include "ipc/ipc_tests.h" |
| 20 | #include "testing/gtest/include/gtest/gtest.h" |
| 21 | #include "testing/multiprocess_func_list.h" |
| 22 | |
brettw@google.com | 7c5cc67 | 2011-01-01 11:17:08 +0900 | [diff] [blame] | 23 | #if defined(OS_LINUX) || defined(OS_MACOSX) |
| 24 | #include "base/file_descriptor_posix.h" |
| 25 | #endif // defined(OS_LINUX) || defined(OS_MACOSX) |
sehr@google.com | 4f325aa | 2009-11-25 01:14:53 +0900 | [diff] [blame] | 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 | |
sehr@google.com | fdc9006 | 2009-11-26 09:28:02 +0900 | [diff] [blame] | 39 | // Message class to pass a base::SyncSocket::Handle to another process. |
| 40 | // This is not as easy as it sounds, because of the differences in transferring |
| 41 | // Windows HANDLEs versus posix file descriptors. |
| 42 | #if defined(OS_WIN) |
sehr@google.com | 4f325aa | 2009-11-25 01:14:53 +0900 | [diff] [blame] | 43 | class MsgClassSetHandle |
| 44 | : public IPC::MessageWithTuple< Tuple1<base::SyncSocket::Handle> > { |
| 45 | public: |
| 46 | enum { ID = SERVER_FIRST_IPC_TYPE }; |
| 47 | explicit MsgClassSetHandle(const base::SyncSocket::Handle arg1) |
| 48 | : IPC::MessageWithTuple< Tuple1<base::SyncSocket::Handle> >( |
| 49 | MSG_ROUTING_CONTROL, ID, MakeRefTuple(arg1)) {} |
| 50 | |
| 51 | private: |
| 52 | DISALLOW_COPY_AND_ASSIGN(MsgClassSetHandle); |
| 53 | }; |
sehr@google.com | fdc9006 | 2009-11-26 09:28:02 +0900 | [diff] [blame] | 54 | #elif defined(OS_POSIX) |
| 55 | class MsgClassSetHandle |
| 56 | : public IPC::MessageWithTuple< Tuple1<base::FileDescriptor> > { |
| 57 | public: |
| 58 | enum { ID = SERVER_FIRST_IPC_TYPE }; |
| 59 | explicit MsgClassSetHandle(const base::FileDescriptor& arg1) |
| 60 | : IPC::MessageWithTuple< Tuple1<base::FileDescriptor> >( |
| 61 | MSG_ROUTING_CONTROL, ID, MakeRefTuple(arg1)) {} |
| 62 | |
| 63 | private: |
| 64 | DISALLOW_COPY_AND_ASSIGN(MsgClassSetHandle); |
| 65 | }; |
| 66 | #else |
| 67 | # error "What platform?" |
| 68 | #endif // defined(OS_WIN) |
sehr@google.com | 4f325aa | 2009-11-25 01:14:53 +0900 | [diff] [blame] | 69 | |
| 70 | // Message class to pass a response to the server. |
| 71 | class MsgClassResponse |
| 72 | : public IPC::MessageWithTuple< Tuple1<std::string> > { |
| 73 | public: |
| 74 | enum { ID = CLIENT_FIRST_IPC_TYPE }; |
| 75 | explicit MsgClassResponse(const std::string& arg1) |
| 76 | : IPC::MessageWithTuple< Tuple1<std::string> >( |
| 77 | MSG_ROUTING_CONTROL, ID, MakeRefTuple(arg1)) {} |
| 78 | |
| 79 | private: |
| 80 | DISALLOW_COPY_AND_ASSIGN(MsgClassResponse); |
| 81 | }; |
| 82 | |
| 83 | // Message class to tell the server to shut down. |
| 84 | class MsgClassShutdown |
| 85 | : public IPC::MessageWithTuple< Tuple0 > { |
| 86 | public: |
| 87 | enum { ID = SERVER_SECOND_IPC_TYPE }; |
| 88 | MsgClassShutdown() |
| 89 | : IPC::MessageWithTuple< Tuple0 >( |
| 90 | MSG_ROUTING_CONTROL, ID, MakeTuple()) {} |
| 91 | |
| 92 | private: |
| 93 | DISALLOW_COPY_AND_ASSIGN(MsgClassShutdown); |
| 94 | }; |
| 95 | |
| 96 | // The SyncSocket server listener class processes two sorts of |
| 97 | // messages from the client. |
| 98 | class SyncSocketServerListener : public IPC::Channel::Listener { |
| 99 | public: |
| 100 | SyncSocketServerListener() : chan_(NULL) { |
| 101 | } |
| 102 | |
| 103 | void Init(IPC::Channel* chan) { |
| 104 | chan_ = chan; |
| 105 | } |
| 106 | |
jam@chromium.org | 8a2c784 | 2010-12-24 15:19:28 +0900 | [diff] [blame] | 107 | virtual bool OnMessageReceived(const IPC::Message& msg) { |
sehr@google.com | 4f325aa | 2009-11-25 01:14:53 +0900 | [diff] [blame] | 108 | if (msg.routing_id() == MSG_ROUTING_CONTROL) { |
| 109 | IPC_BEGIN_MESSAGE_MAP(SyncSocketServerListener, msg) |
| 110 | IPC_MESSAGE_HANDLER(MsgClassSetHandle, OnMsgClassSetHandle) |
| 111 | IPC_MESSAGE_HANDLER(MsgClassShutdown, OnMsgClassShutdown) |
| 112 | IPC_END_MESSAGE_MAP() |
| 113 | } |
jam@chromium.org | 8a2c784 | 2010-12-24 15:19:28 +0900 | [diff] [blame] | 114 | return true; |
sehr@google.com | 4f325aa | 2009-11-25 01:14:53 +0900 | [diff] [blame] | 115 | } |
| 116 | |
| 117 | private: |
| 118 | // This sort of message is sent first, causing the transfer of |
| 119 | // the handle for the SyncSocket. This message sends a buffer |
| 120 | // on the SyncSocket and then sends a response to the client. |
sehr@google.com | fdc9006 | 2009-11-26 09:28:02 +0900 | [diff] [blame] | 121 | #if defined(OS_WIN) |
sehr@google.com | 4f325aa | 2009-11-25 01:14:53 +0900 | [diff] [blame] | 122 | void OnMsgClassSetHandle(const base::SyncSocket::Handle handle) { |
sehr@google.com | fdc9006 | 2009-11-26 09:28:02 +0900 | [diff] [blame] | 123 | SetHandle(handle); |
| 124 | } |
| 125 | #elif defined(OS_POSIX) |
| 126 | void OnMsgClassSetHandle(const base::FileDescriptor& fd_struct) { |
| 127 | SetHandle(fd_struct.fd); |
| 128 | } |
| 129 | #else |
| 130 | # error "What platform?" |
| 131 | #endif // defined(OS_WIN) |
| 132 | |
| 133 | void SetHandle(base::SyncSocket::Handle handle) { |
sehr@google.com | 4f325aa | 2009-11-25 01:14:53 +0900 | [diff] [blame] | 134 | base::SyncSocket sync_socket(handle); |
| 135 | EXPECT_EQ(sync_socket.Send(static_cast<const void*>(kHelloString), |
| 136 | kHelloStringLength), kHelloStringLength); |
| 137 | IPC::Message* msg = new MsgClassResponse(kHelloString); |
sehr@google.com | 4f325aa | 2009-11-25 01:14:53 +0900 | [diff] [blame] | 138 | EXPECT_TRUE(chan_->Send(msg)); |
| 139 | } |
| 140 | |
| 141 | // When the client responds, it sends back a shutdown message, |
| 142 | // which causes the message loop to exit. |
| 143 | void OnMsgClassShutdown() { |
| 144 | MessageLoop::current()->Quit(); |
| 145 | } |
| 146 | |
| 147 | IPC::Channel* chan_; |
| 148 | |
| 149 | DISALLOW_COPY_AND_ASSIGN(SyncSocketServerListener); |
| 150 | }; |
| 151 | |
| 152 | // Runs the fuzzing server child mode. Returns when the preset number |
| 153 | // of messages have been received. |
| 154 | MULTIPROCESS_TEST_MAIN(RunSyncSocketServer) { |
| 155 | MessageLoopForIO main_message_loop; |
| 156 | SyncSocketServerListener listener; |
| 157 | IPC::Channel chan(kSyncSocketChannel, IPC::Channel::MODE_CLIENT, &listener); |
| 158 | EXPECT_TRUE(chan.Connect()); |
| 159 | listener.Init(&chan); |
| 160 | MessageLoop::current()->Run(); |
| 161 | return 0; |
| 162 | } |
| 163 | |
| 164 | // The SyncSocket client listener only processes one sort of message, |
| 165 | // a response from the server. |
| 166 | class SyncSocketClientListener : public IPC::Channel::Listener { |
| 167 | public: |
| 168 | SyncSocketClientListener() { |
| 169 | } |
| 170 | |
| 171 | void Init(base::SyncSocket* socket, IPC::Channel* chan) { |
| 172 | socket_ = socket; |
| 173 | chan_ = chan; |
| 174 | } |
| 175 | |
jam@chromium.org | 8a2c784 | 2010-12-24 15:19:28 +0900 | [diff] [blame] | 176 | virtual bool OnMessageReceived(const IPC::Message& msg) { |
sehr@google.com | 4f325aa | 2009-11-25 01:14:53 +0900 | [diff] [blame] | 177 | if (msg.routing_id() == MSG_ROUTING_CONTROL) { |
| 178 | IPC_BEGIN_MESSAGE_MAP(SyncSocketClientListener, msg) |
| 179 | IPC_MESSAGE_HANDLER(MsgClassResponse, OnMsgClassResponse) |
| 180 | IPC_END_MESSAGE_MAP() |
| 181 | } |
jam@chromium.org | 8a2c784 | 2010-12-24 15:19:28 +0900 | [diff] [blame] | 182 | return true; |
sehr@google.com | 4f325aa | 2009-11-25 01:14:53 +0900 | [diff] [blame] | 183 | } |
| 184 | |
| 185 | private: |
| 186 | // When a response is received from the server, it sends the same |
| 187 | // string as was written on the SyncSocket. These are compared |
| 188 | // and a shutdown message is sent back to the server. |
| 189 | void OnMsgClassResponse(const std::string& str) { |
cpu@chromium.org | 750392c | 2009-12-05 07:53:22 +0900 | [diff] [blame] | 190 | // We rely on the order of sync_socket.Send() and chan_->Send() in |
| 191 | // the SyncSocketServerListener object. |
| 192 | EXPECT_EQ(kHelloStringLength, socket_->Peek()); |
sehr@google.com | 4f325aa | 2009-11-25 01:14:53 +0900 | [diff] [blame] | 193 | char buf[kHelloStringLength]; |
| 194 | socket_->Receive(static_cast<void*>(buf), kHelloStringLength); |
| 195 | EXPECT_EQ(strcmp(str.c_str(), buf), 0); |
sehr@google.com | b72918f | 2009-12-07 04:45:08 +0900 | [diff] [blame] | 196 | // After receiving from the socket there should be no bytes left. |
thomasvl@google.com | 9a24207 | 2010-07-23 23:18:59 +0900 | [diff] [blame] | 197 | EXPECT_EQ(0U, socket_->Peek()); |
sehr@google.com | 4f325aa | 2009-11-25 01:14:53 +0900 | [diff] [blame] | 198 | IPC::Message* msg = new MsgClassShutdown(); |
sehr@google.com | 4f325aa | 2009-11-25 01:14:53 +0900 | [diff] [blame] | 199 | EXPECT_TRUE(chan_->Send(msg)); |
| 200 | MessageLoop::current()->Quit(); |
| 201 | } |
| 202 | |
| 203 | base::SyncSocket* socket_; |
| 204 | IPC::Channel* chan_; |
| 205 | |
| 206 | DISALLOW_COPY_AND_ASSIGN(SyncSocketClientListener); |
| 207 | }; |
| 208 | |
| 209 | class SyncSocketTest : public IPCChannelTest { |
| 210 | }; |
| 211 | |
| 212 | TEST_F(SyncSocketTest, SanityTest) { |
| 213 | SyncSocketClientListener listener; |
| 214 | IPC::Channel chan(kSyncSocketChannel, IPC::Channel::MODE_SERVER, |
| 215 | &listener); |
| 216 | base::ProcessHandle server_process = SpawnChild(SYNC_SOCKET_SERVER, &chan); |
| 217 | ASSERT_TRUE(server_process); |
| 218 | // Create a pair of SyncSockets. |
| 219 | base::SyncSocket* pair[2]; |
| 220 | base::SyncSocket::CreatePair(pair); |
sehr@google.com | b72918f | 2009-12-07 04:45:08 +0900 | [diff] [blame] | 221 | // Immediately after creation there should be no pending bytes. |
thomasvl@google.com | 9a24207 | 2010-07-23 23:18:59 +0900 | [diff] [blame] | 222 | EXPECT_EQ(0U, pair[0]->Peek()); |
| 223 | EXPECT_EQ(0U, pair[1]->Peek()); |
sehr@google.com | 4f325aa | 2009-11-25 01:14:53 +0900 | [diff] [blame] | 224 | base::SyncSocket::Handle target_handle; |
sehr@google.com | fdc9006 | 2009-11-26 09:28:02 +0900 | [diff] [blame] | 225 | // Connect the channel and listener. |
| 226 | ASSERT_TRUE(chan.Connect()); |
| 227 | listener.Init(pair[0], &chan); |
sehr@google.com | 4f325aa | 2009-11-25 01:14:53 +0900 | [diff] [blame] | 228 | #if defined(OS_WIN) |
| 229 | // On windows we need to duplicate the handle into the server process. |
| 230 | BOOL retval = DuplicateHandle(GetCurrentProcess(), pair[1]->handle(), |
| 231 | server_process, &target_handle, |
| 232 | 0, FALSE, DUPLICATE_SAME_ACCESS); |
| 233 | EXPECT_TRUE(retval); |
sehr@google.com | 4f325aa | 2009-11-25 01:14:53 +0900 | [diff] [blame] | 234 | // Set up a message to pass the handle to the server. |
| 235 | IPC::Message* msg = new MsgClassSetHandle(target_handle); |
sehr@google.com | fdc9006 | 2009-11-26 09:28:02 +0900 | [diff] [blame] | 236 | #else |
| 237 | target_handle = pair[1]->handle(); |
| 238 | // Set up a message to pass the handle to the server. |
| 239 | base::FileDescriptor filedesc(target_handle, false); |
| 240 | IPC::Message* msg = new MsgClassSetHandle(filedesc); |
| 241 | #endif // defined(OS_WIN) |
sehr@google.com | 4f325aa | 2009-11-25 01:14:53 +0900 | [diff] [blame] | 242 | EXPECT_TRUE(chan.Send(msg)); |
| 243 | // Use the current thread as the I/O thread. |
| 244 | MessageLoop::current()->Run(); |
| 245 | // Shut down. |
| 246 | delete pair[0]; |
| 247 | delete pair[1]; |
| 248 | EXPECT_TRUE(base::WaitForSingleProcess(server_process, 5000)); |
| 249 | base::CloseProcessHandle(server_process); |
| 250 | } |