| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 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 "base/basictypes.h" | |
| 6 #include "sandbox/src/crosscall_client.h" | |
| 7 #include "sandbox/src/crosscall_server.h" | |
| 8 #include "sandbox/src/sharedmem_ipc_client.h" | |
| 9 #include "sandbox/src/sharedmem_ipc_server.h" | |
| 10 #include "testing/gtest/include/gtest/gtest.h" | |
| 11 | |
| 12 namespace sandbox { | |
| 13 | |
| 14 // Helper function to make the fake shared memory with some | |
| 15 // basic elements initialized. | |
| 16 IPCControl* MakeChannels(size_t channel_size, size_t total_shared_size, | |
| 17 size_t* base_start) { | |
| 18 // Allocate memory | |
| 19 char* mem = new char[total_shared_size]; | |
| 20 memset(mem, 0, total_shared_size); | |
| 21 // Calculate how many channels we can fit in the shared memory. | |
| 22 total_shared_size -= offsetof(IPCControl, channels); | |
| 23 size_t channel_count = | |
| 24 total_shared_size / (sizeof(ChannelControl) + channel_size); | |
| 25 // Calculate the start of the first channel. | |
| 26 *base_start = (sizeof(ChannelControl)* channel_count) + | |
| 27 offsetof(IPCControl, channels); | |
| 28 // Setup client structure. | |
| 29 IPCControl* client_control = reinterpret_cast<IPCControl*>(mem); | |
| 30 client_control->channels_count = channel_count; | |
| 31 return client_control; | |
| 32 } | |
| 33 | |
| 34 enum TestFixMode { | |
| 35 FIX_NO_EVENTS, | |
| 36 FIX_PONG_READY, | |
| 37 FIX_PONG_NOT_READY | |
| 38 }; | |
| 39 | |
| 40 void FixChannels(IPCControl* client_control, size_t base_start, | |
| 41 size_t channel_size, TestFixMode mode) { | |
| 42 for (size_t ix = 0; ix != client_control->channels_count; ++ix) { | |
| 43 ChannelControl& channel = client_control->channels[ix]; | |
| 44 channel.channel_base = base_start; | |
| 45 channel.state = kFreeChannel; | |
| 46 if (mode != FIX_NO_EVENTS) { | |
| 47 BOOL signaled = (FIX_PONG_READY == mode)? TRUE : FALSE; | |
| 48 channel.ping_event = ::CreateEventW(NULL, FALSE, FALSE, NULL); | |
| 49 channel.pong_event = ::CreateEventW(NULL, FALSE, signaled, NULL); | |
| 50 } | |
| 51 base_start += channel_size; | |
| 52 } | |
| 53 } | |
| 54 | |
| 55 void CloseChannelEvents(IPCControl* client_control) { | |
| 56 for (size_t ix = 0; ix != client_control->channels_count; ++ix) { | |
| 57 ChannelControl& channel = client_control->channels[ix]; | |
| 58 ::CloseHandle(channel.ping_event); | |
| 59 ::CloseHandle(channel.pong_event); | |
| 60 } | |
| 61 } | |
| 62 | |
| 63 TEST(IPCTest, ChannelMaker) { | |
| 64 // Test that our testing rig is computing offsets properly. We should have | |
| 65 // 5 channnels and the offset to the first channel is 108 bytes in 32 bits | |
| 66 // and 216 in 64 bits. | |
| 67 size_t channel_start = 0; | |
| 68 IPCControl* client_control = MakeChannels(12 * 64, 4096, &channel_start); | |
| 69 ASSERT_TRUE(NULL != client_control); | |
| 70 EXPECT_EQ(5, client_control->channels_count); | |
| 71 #if defined(_WIN64) | |
| 72 EXPECT_EQ(216, channel_start); | |
| 73 #else | |
| 74 EXPECT_EQ(108, channel_start); | |
| 75 #endif | |
| 76 delete[] reinterpret_cast<char*>(client_control); | |
| 77 } | |
| 78 | |
| 79 TEST(IPCTest, ClientLockUnlock) { | |
| 80 // Make 7 channels of kIPCChannelSize (1kb) each. Test that we lock and | |
| 81 // unlock channels properly. | |
| 82 size_t base_start = 0; | |
| 83 IPCControl* client_control = | |
| 84 MakeChannels(kIPCChannelSize, 4096 * 2, &base_start); | |
| 85 FixChannels(client_control, base_start, kIPCChannelSize, FIX_NO_EVENTS); | |
| 86 | |
| 87 char* mem = reinterpret_cast<char*>(client_control); | |
| 88 SharedMemIPCClient client(mem); | |
| 89 | |
| 90 // Test that we lock the first 3 channels in sequence. | |
| 91 void* buff0 = client.GetBuffer(); | |
| 92 EXPECT_TRUE(mem + client_control->channels[0].channel_base == buff0); | |
| 93 EXPECT_EQ(kBusyChannel, client_control->channels[0].state); | |
| 94 EXPECT_EQ(kFreeChannel, client_control->channels[1].state); | |
| 95 EXPECT_EQ(kFreeChannel, client_control->channels[2].state); | |
| 96 EXPECT_EQ(kFreeChannel, client_control->channels[3].state); | |
| 97 EXPECT_EQ(kFreeChannel, client_control->channels[4].state); | |
| 98 EXPECT_EQ(kFreeChannel, client_control->channels[5].state); | |
| 99 | |
| 100 void* buff1 = client.GetBuffer(); | |
| 101 EXPECT_TRUE(mem + client_control->channels[1].channel_base == buff1); | |
| 102 EXPECT_EQ(kBusyChannel, client_control->channels[0].state); | |
| 103 EXPECT_EQ(kBusyChannel, client_control->channels[1].state); | |
| 104 EXPECT_EQ(kFreeChannel, client_control->channels[2].state); | |
| 105 EXPECT_EQ(kFreeChannel, client_control->channels[3].state); | |
| 106 EXPECT_EQ(kFreeChannel, client_control->channels[4].state); | |
| 107 EXPECT_EQ(kFreeChannel, client_control->channels[5].state); | |
| 108 | |
| 109 void* buff2 = client.GetBuffer(); | |
| 110 EXPECT_TRUE(mem + client_control->channels[2].channel_base == buff2); | |
| 111 EXPECT_EQ(kBusyChannel, client_control->channels[0].state); | |
| 112 EXPECT_EQ(kBusyChannel, client_control->channels[1].state); | |
| 113 EXPECT_EQ(kBusyChannel, client_control->channels[2].state); | |
| 114 EXPECT_EQ(kFreeChannel, client_control->channels[3].state); | |
| 115 EXPECT_EQ(kFreeChannel, client_control->channels[4].state); | |
| 116 EXPECT_EQ(kFreeChannel, client_control->channels[5].state); | |
| 117 | |
| 118 // Test that we unlock and re-lock the right channel. | |
| 119 client.FreeBuffer(buff1); | |
| 120 EXPECT_EQ(kBusyChannel, client_control->channels[0].state); | |
| 121 EXPECT_EQ(kFreeChannel, client_control->channels[1].state); | |
| 122 EXPECT_EQ(kBusyChannel, client_control->channels[2].state); | |
| 123 EXPECT_EQ(kFreeChannel, client_control->channels[3].state); | |
| 124 EXPECT_EQ(kFreeChannel, client_control->channels[4].state); | |
| 125 EXPECT_EQ(kFreeChannel, client_control->channels[5].state); | |
| 126 | |
| 127 void* buff2b = client.GetBuffer(); | |
| 128 EXPECT_TRUE(mem + client_control->channels[1].channel_base == buff2b); | |
| 129 EXPECT_EQ(kBusyChannel, client_control->channels[0].state); | |
| 130 EXPECT_EQ(kBusyChannel, client_control->channels[1].state); | |
| 131 EXPECT_EQ(kBusyChannel, client_control->channels[2].state); | |
| 132 EXPECT_EQ(kFreeChannel, client_control->channels[3].state); | |
| 133 EXPECT_EQ(kFreeChannel, client_control->channels[4].state); | |
| 134 EXPECT_EQ(kFreeChannel, client_control->channels[5].state); | |
| 135 | |
| 136 client.FreeBuffer(buff0); | |
| 137 EXPECT_EQ(kFreeChannel, client_control->channels[0].state); | |
| 138 EXPECT_EQ(kBusyChannel, client_control->channels[1].state); | |
| 139 EXPECT_EQ(kBusyChannel, client_control->channels[2].state); | |
| 140 EXPECT_EQ(kFreeChannel, client_control->channels[3].state); | |
| 141 EXPECT_EQ(kFreeChannel, client_control->channels[4].state); | |
| 142 EXPECT_EQ(kFreeChannel, client_control->channels[5].state); | |
| 143 | |
| 144 delete[] reinterpret_cast<char*>(client_control); | |
| 145 } | |
| 146 | |
| 147 TEST(IPCTest, CrossCallStrPacking) { | |
| 148 // This test tries the CrossCall object with null and non-null string | |
| 149 // combination of parameters, integer types and verifies that the unpacker | |
| 150 // can read them properly. | |
| 151 size_t base_start = 0; | |
| 152 IPCControl* client_control = | |
| 153 MakeChannels(kIPCChannelSize, 4096 * 4, &base_start); | |
| 154 client_control->server_alive = HANDLE(1); | |
| 155 FixChannels(client_control, base_start, kIPCChannelSize, FIX_PONG_READY); | |
| 156 | |
| 157 char* mem = reinterpret_cast<char*>(client_control); | |
| 158 SharedMemIPCClient client(mem); | |
| 159 | |
| 160 CrossCallReturn answer; | |
| 161 uint32 tag1 = 666; | |
| 162 const wchar_t text[] = L"98765 - 43210"; | |
| 163 std::wstring copied_text; | |
| 164 CrossCallParamsEx* actual_params; | |
| 165 | |
| 166 CrossCall(client, tag1, text, &answer); | |
| 167 actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer()); | |
| 168 EXPECT_EQ(1, actual_params->GetParamsCount()); | |
| 169 EXPECT_EQ(tag1, actual_params->GetTag()); | |
| 170 EXPECT_TRUE(actual_params->GetParameterStr(0, &copied_text)); | |
| 171 EXPECT_STREQ(text, copied_text.c_str()); | |
| 172 | |
| 173 // Check with an empty string. | |
| 174 uint32 tag2 = 777; | |
| 175 const wchar_t* null_text = NULL; | |
| 176 CrossCall(client, tag2, null_text, &answer); | |
| 177 actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer()); | |
| 178 EXPECT_EQ(1, actual_params->GetParamsCount()); | |
| 179 EXPECT_EQ(tag2, actual_params->GetTag()); | |
| 180 uint32 param_size = 1; | |
| 181 ArgType type = INVALID_TYPE; | |
| 182 void* param_addr = actual_params->GetRawParameter(0, ¶m_size, &type); | |
| 183 EXPECT_TRUE(NULL != param_addr); | |
| 184 EXPECT_EQ(0, param_size); | |
| 185 EXPECT_EQ(WCHAR_TYPE, type); | |
| 186 EXPECT_TRUE(actual_params->GetParameterStr(0, &copied_text)); | |
| 187 | |
| 188 uint32 tag3 = 888; | |
| 189 param_size = 1; | |
| 190 copied_text.clear(); | |
| 191 | |
| 192 // Check with an empty string and a non-empty string. | |
| 193 CrossCall(client, tag3, null_text, text, &answer); | |
| 194 actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer()); | |
| 195 EXPECT_EQ(2, actual_params->GetParamsCount()); | |
| 196 EXPECT_EQ(tag3, actual_params->GetTag()); | |
| 197 type = INVALID_TYPE; | |
| 198 param_addr = actual_params->GetRawParameter(0, ¶m_size, &type); | |
| 199 EXPECT_TRUE(NULL != param_addr); | |
| 200 EXPECT_EQ(0, param_size); | |
| 201 EXPECT_EQ(WCHAR_TYPE, type); | |
| 202 EXPECT_TRUE(actual_params->GetParameterStr(0, &copied_text)); | |
| 203 EXPECT_TRUE(actual_params->GetParameterStr(1, &copied_text)); | |
| 204 EXPECT_STREQ(text, copied_text.c_str()); | |
| 205 | |
| 206 param_size = 1; | |
| 207 std::wstring copied_text_p0, copied_text_p2; | |
| 208 | |
| 209 const wchar_t text2[] = L"AeFG"; | |
| 210 CrossCall(client, tag1, text2, null_text, text, &answer); | |
| 211 actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer()); | |
| 212 EXPECT_EQ(3, actual_params->GetParamsCount()); | |
| 213 EXPECT_EQ(tag1, actual_params->GetTag()); | |
| 214 EXPECT_TRUE(actual_params->GetParameterStr(0, &copied_text_p0)); | |
| 215 EXPECT_STREQ(text2, copied_text_p0.c_str()); | |
| 216 EXPECT_TRUE(actual_params->GetParameterStr(2, &copied_text_p2)); | |
| 217 EXPECT_STREQ(text, copied_text_p2.c_str()); | |
| 218 type = INVALID_TYPE; | |
| 219 param_addr = actual_params->GetRawParameter(1, ¶m_size, &type); | |
| 220 EXPECT_TRUE(NULL != param_addr); | |
| 221 EXPECT_EQ(0, param_size); | |
| 222 EXPECT_EQ(WCHAR_TYPE, type); | |
| 223 | |
| 224 CloseChannelEvents(client_control); | |
| 225 delete[] reinterpret_cast<char*>(client_control); | |
| 226 } | |
| 227 | |
| 228 TEST(IPCTest, CrossCallIntPacking) { | |
| 229 // Check handling for regular 32 bit integers used in Windows. | |
| 230 size_t base_start = 0; | |
| 231 IPCControl* client_control = | |
| 232 MakeChannels(kIPCChannelSize, 4096 * 4, &base_start); | |
| 233 client_control->server_alive = HANDLE(1); | |
| 234 FixChannels(client_control, base_start, kIPCChannelSize, FIX_PONG_READY); | |
| 235 | |
| 236 uint32 tag1 = 999; | |
| 237 uint32 tag2 = 111; | |
| 238 const wchar_t text[] = L"godzilla"; | |
| 239 CrossCallParamsEx* actual_params; | |
| 240 | |
| 241 char* mem = reinterpret_cast<char*>(client_control); | |
| 242 SharedMemIPCClient client(mem); | |
| 243 | |
| 244 CrossCallReturn answer; | |
| 245 DWORD dw = 0xE6578; | |
| 246 CrossCall(client, tag2, dw, &answer); | |
| 247 actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer()); | |
| 248 EXPECT_EQ(1, actual_params->GetParamsCount()); | |
| 249 EXPECT_EQ(tag2, actual_params->GetTag()); | |
| 250 ArgType type = INVALID_TYPE; | |
| 251 uint32 param_size = 1; | |
| 252 void* param_addr = actual_params->GetRawParameter(0, ¶m_size, &type); | |
| 253 ASSERT_EQ(sizeof(dw), param_size); | |
| 254 EXPECT_EQ(ULONG_TYPE, type); | |
| 255 ASSERT_TRUE(NULL != param_addr); | |
| 256 EXPECT_EQ(0, memcmp(&dw, param_addr, param_size)); | |
| 257 | |
| 258 // Check handling for windows HANDLES. | |
| 259 HANDLE h = HANDLE(0x70000500); | |
| 260 CrossCall(client, tag1, text, h, &answer); | |
| 261 actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer()); | |
| 262 EXPECT_EQ(2, actual_params->GetParamsCount()); | |
| 263 EXPECT_EQ(tag1, actual_params->GetTag()); | |
| 264 type = INVALID_TYPE; | |
| 265 param_addr = actual_params->GetRawParameter(1, ¶m_size, &type); | |
| 266 ASSERT_EQ(sizeof(h), param_size); | |
| 267 EXPECT_EQ(VOIDPTR_TYPE, type); | |
| 268 ASSERT_TRUE(NULL != param_addr); | |
| 269 EXPECT_EQ(0, memcmp(&h, param_addr, param_size)); | |
| 270 | |
| 271 // Check combination of 32 and 64 bits. | |
| 272 CrossCall(client, tag2, h, dw, h, &answer); | |
| 273 actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer()); | |
| 274 EXPECT_EQ(3, actual_params->GetParamsCount()); | |
| 275 EXPECT_EQ(tag2, actual_params->GetTag()); | |
| 276 type = INVALID_TYPE; | |
| 277 param_addr = actual_params->GetRawParameter(0, ¶m_size, &type); | |
| 278 ASSERT_EQ(sizeof(h), param_size); | |
| 279 EXPECT_EQ(VOIDPTR_TYPE, type); | |
| 280 ASSERT_TRUE(NULL != param_addr); | |
| 281 EXPECT_EQ(0, memcmp(&h, param_addr, param_size)); | |
| 282 type = INVALID_TYPE; | |
| 283 param_addr = actual_params->GetRawParameter(1, ¶m_size, &type); | |
| 284 ASSERT_EQ(sizeof(dw), param_size); | |
| 285 EXPECT_EQ(ULONG_TYPE, type); | |
| 286 ASSERT_TRUE(NULL != param_addr); | |
| 287 EXPECT_EQ(0, memcmp(&dw, param_addr, param_size)); | |
| 288 type = INVALID_TYPE; | |
| 289 param_addr = actual_params->GetRawParameter(2, ¶m_size, &type); | |
| 290 ASSERT_EQ(sizeof(h), param_size); | |
| 291 EXPECT_EQ(VOIDPTR_TYPE, type); | |
| 292 ASSERT_TRUE(NULL != param_addr); | |
| 293 EXPECT_EQ(0, memcmp(&h, param_addr, param_size)); | |
| 294 | |
| 295 CloseChannelEvents(client_control); | |
| 296 delete[] reinterpret_cast<char*>(client_control); | |
| 297 } | |
| 298 | |
| 299 TEST(IPCTest, CrossCallValidation) { | |
| 300 // First a sanity test with a well formed parameter object. | |
| 301 unsigned long value = 124816; | |
| 302 const uint32 kTag = 33; | |
| 303 const uint32 kBufferSize = 256; | |
| 304 ActualCallParams<1, kBufferSize> params_1(kTag); | |
| 305 params_1.CopyParamIn(0, &value, sizeof(value), false, ULONG_TYPE); | |
| 306 void* buffer = const_cast<void*>(params_1.GetBuffer()); | |
| 307 | |
| 308 uint32 out_size = 0; | |
| 309 CrossCallParamsEx* ccp = 0; | |
| 310 ccp = CrossCallParamsEx::CreateFromBuffer(buffer, params_1.GetSize(), | |
| 311 &out_size); | |
| 312 ASSERT_TRUE(NULL != ccp); | |
| 313 EXPECT_TRUE(ccp->GetBuffer() != buffer); | |
| 314 EXPECT_EQ(kTag, ccp->GetTag()); | |
| 315 EXPECT_EQ(1, ccp->GetParamsCount()); | |
| 316 delete[] (reinterpret_cast<char*>(ccp)); | |
| 317 | |
| 318 #if defined(NDEBUG) | |
| 319 // Test hat we handle integer overflow on the number of params | |
| 320 // correctly. We use a test-only ctor for ActualCallParams that | |
| 321 // allows to create malformed cross-call buffers. | |
| 322 const int32 kPtrDiffSz = sizeof(ptrdiff_t); | |
| 323 for (int32 ix = -1; ix != 3; ++ix) { | |
| 324 uint32 fake_num_params = (kuint32max / kPtrDiffSz) + ix; | |
| 325 ActualCallParams<1, kBufferSize> params_2(kTag, fake_num_params); | |
| 326 params_2.CopyParamIn(0, &value, sizeof(value), false, ULONG_TYPE); | |
| 327 buffer = const_cast<void*>(params_2.GetBuffer()); | |
| 328 | |
| 329 EXPECT_TRUE(NULL != buffer); | |
| 330 ccp = CrossCallParamsEx::CreateFromBuffer(buffer, params_1.GetSize(), | |
| 331 &out_size); | |
| 332 // If the buffer is malformed the return is NULL. | |
| 333 EXPECT_TRUE(NULL == ccp); | |
| 334 } | |
| 335 #endif // defined(NDEBUG) | |
| 336 | |
| 337 ActualCallParams<1, kBufferSize> params_3(kTag, 1); | |
| 338 params_3.CopyParamIn(0, &value, sizeof(value), false, ULONG_TYPE); | |
| 339 buffer = const_cast<void*>(params_3.GetBuffer()); | |
| 340 EXPECT_TRUE(NULL != buffer); | |
| 341 | |
| 342 uint32 correct_size = params_3.OverrideSize(1); | |
| 343 ccp = CrossCallParamsEx::CreateFromBuffer(buffer, kBufferSize, &out_size); | |
| 344 EXPECT_TRUE(NULL == ccp); | |
| 345 | |
| 346 // The correct_size is 8 bytes aligned. | |
| 347 params_3.OverrideSize(correct_size - 7); | |
| 348 ccp = CrossCallParamsEx::CreateFromBuffer(buffer, kBufferSize, &out_size); | |
| 349 EXPECT_TRUE(NULL == ccp); | |
| 350 | |
| 351 params_3.OverrideSize(correct_size); | |
| 352 ccp = CrossCallParamsEx::CreateFromBuffer(buffer, kBufferSize, &out_size); | |
| 353 EXPECT_TRUE(NULL != ccp); | |
| 354 | |
| 355 // Make sure that two parameters work as expected. | |
| 356 ActualCallParams<2, kBufferSize> params_4(kTag, 2); | |
| 357 params_4.CopyParamIn(0, &value, sizeof(value), false, ULONG_TYPE); | |
| 358 params_4.CopyParamIn(1, buffer, sizeof(buffer), false, VOIDPTR_TYPE); | |
| 359 buffer = const_cast<void*>(params_4.GetBuffer()); | |
| 360 EXPECT_TRUE(NULL != buffer); | |
| 361 | |
| 362 ccp = CrossCallParamsEx::CreateFromBuffer(buffer, kBufferSize, &out_size); | |
| 363 EXPECT_TRUE(NULL != ccp); | |
| 364 | |
| 365 #if defined(_WIN64) | |
| 366 correct_size = params_4.OverrideSize(1); | |
| 367 params_4.OverrideSize(correct_size - 1); | |
| 368 ccp = CrossCallParamsEx::CreateFromBuffer(buffer, kBufferSize, &out_size); | |
| 369 EXPECT_TRUE(NULL == ccp); | |
| 370 #endif | |
| 371 } | |
| 372 | |
| 373 // This structure is passed to the mock server threads to simulate | |
| 374 // the server side IPC so it has the required kernel objects. | |
| 375 struct ServerEvents { | |
| 376 HANDLE ping; | |
| 377 HANDLE pong; | |
| 378 volatile LONG* state; | |
| 379 HANDLE mutex; | |
| 380 }; | |
| 381 | |
| 382 // This is the server thread that quicky answers an IPC and exits. | |
| 383 DWORD WINAPI QuickResponseServer(PVOID param) { | |
| 384 ServerEvents* events = reinterpret_cast<ServerEvents*>(param); | |
| 385 DWORD wait_result = 0; | |
| 386 wait_result = ::WaitForSingleObject(events->ping, INFINITE); | |
| 387 ::InterlockedExchange(events->state, kAckChannel); | |
| 388 ::SetEvent(events->pong); | |
| 389 return wait_result; | |
| 390 } | |
| 391 | |
| 392 class CrossCallParamsMock : public CrossCallParams { | |
| 393 public: | |
| 394 CrossCallParamsMock(uint32 tag, uint32 params_count) | |
| 395 : CrossCallParams(tag, params_count) { | |
| 396 } | |
| 397 private: | |
| 398 void* params[4]; | |
| 399 }; | |
| 400 | |
| 401 void FakeOkAnswerInChannel(void* channel) { | |
| 402 CrossCallReturn* answer = reinterpret_cast<CrossCallReturn*>(channel); | |
| 403 answer->call_outcome = SBOX_ALL_OK; | |
| 404 } | |
| 405 | |
| 406 // Create two threads that will quickly answer IPCs; the first one | |
| 407 // using channel 1 (channel 0 is busy) and one using channel 0. No time-out | |
| 408 // should occur. | |
| 409 TEST(IPCTest, ClientFastServer) { | |
| 410 const size_t channel_size = kIPCChannelSize; | |
| 411 size_t base_start = 0; | |
| 412 IPCControl* client_control = | |
| 413 MakeChannels(channel_size, 4096 * 2, &base_start); | |
| 414 FixChannels(client_control, base_start, kIPCChannelSize, FIX_PONG_NOT_READY); | |
| 415 client_control->server_alive = ::CreateMutex(NULL, FALSE, NULL); | |
| 416 | |
| 417 char* mem = reinterpret_cast<char*>(client_control); | |
| 418 SharedMemIPCClient client(mem); | |
| 419 | |
| 420 ServerEvents events = {0}; | |
| 421 events.ping = client_control->channels[1].ping_event; | |
| 422 events.pong = client_control->channels[1].pong_event; | |
| 423 events.state = &client_control->channels[1].state; | |
| 424 | |
| 425 HANDLE t1 = ::CreateThread(NULL, 0, QuickResponseServer, &events, 0, NULL); | |
| 426 ASSERT_TRUE(NULL != t1); | |
| 427 ::CloseHandle(t1); | |
| 428 | |
| 429 void* buff0 = client.GetBuffer(); | |
| 430 EXPECT_TRUE(mem + client_control->channels[0].channel_base == buff0); | |
| 431 EXPECT_EQ(kBusyChannel, client_control->channels[0].state); | |
| 432 EXPECT_EQ(kFreeChannel, client_control->channels[1].state); | |
| 433 EXPECT_EQ(kFreeChannel, client_control->channels[2].state); | |
| 434 | |
| 435 void* buff1 = client.GetBuffer(); | |
| 436 EXPECT_TRUE(mem + client_control->channels[1].channel_base == buff1); | |
| 437 EXPECT_EQ(kBusyChannel, client_control->channels[0].state); | |
| 438 EXPECT_EQ(kBusyChannel, client_control->channels[1].state); | |
| 439 EXPECT_EQ(kFreeChannel, client_control->channels[2].state); | |
| 440 | |
| 441 EXPECT_EQ(0, client_control->channels[1].ipc_tag); | |
| 442 | |
| 443 uint32 tag = 7654; | |
| 444 CrossCallReturn answer; | |
| 445 CrossCallParamsMock* params1 = new(buff1) CrossCallParamsMock(tag, 1); | |
| 446 FakeOkAnswerInChannel(buff1); | |
| 447 | |
| 448 ResultCode result = client.DoCall(params1, &answer); | |
| 449 if (SBOX_ERROR_CHANNEL_ERROR != result) | |
| 450 client.FreeBuffer(buff1); | |
| 451 | |
| 452 EXPECT_TRUE(SBOX_ALL_OK == result); | |
| 453 EXPECT_EQ(tag, client_control->channels[1].ipc_tag); | |
| 454 EXPECT_EQ(kBusyChannel, client_control->channels[0].state); | |
| 455 EXPECT_EQ(kFreeChannel, client_control->channels[1].state); | |
| 456 EXPECT_EQ(kFreeChannel, client_control->channels[2].state); | |
| 457 | |
| 458 HANDLE t2 = ::CreateThread(NULL, 0, QuickResponseServer, &events, 0, NULL); | |
| 459 ASSERT_TRUE(NULL != t2); | |
| 460 ::CloseHandle(t2); | |
| 461 | |
| 462 client.FreeBuffer(buff0); | |
| 463 events.ping = client_control->channels[0].ping_event; | |
| 464 events.pong = client_control->channels[0].pong_event; | |
| 465 events.state = &client_control->channels[0].state; | |
| 466 | |
| 467 tag = 4567; | |
| 468 CrossCallParamsMock* params2 = new(buff0) CrossCallParamsMock(tag, 1); | |
| 469 FakeOkAnswerInChannel(buff0); | |
| 470 | |
| 471 result = client.DoCall(params2, &answer); | |
| 472 if (SBOX_ERROR_CHANNEL_ERROR != result) | |
| 473 client.FreeBuffer(buff0); | |
| 474 | |
| 475 EXPECT_TRUE(SBOX_ALL_OK == result); | |
| 476 EXPECT_EQ(tag, client_control->channels[0].ipc_tag); | |
| 477 EXPECT_EQ(kFreeChannel, client_control->channels[0].state); | |
| 478 EXPECT_EQ(kFreeChannel, client_control->channels[1].state); | |
| 479 EXPECT_EQ(kFreeChannel, client_control->channels[2].state); | |
| 480 | |
| 481 CloseChannelEvents(client_control); | |
| 482 ::CloseHandle(client_control->server_alive); | |
| 483 | |
| 484 delete[] reinterpret_cast<char*>(client_control); | |
| 485 } | |
| 486 | |
| 487 // This is the server thread that very slowly answers an IPC and exits. Note | |
| 488 // that the pong event needs to be signaled twice. | |
| 489 DWORD WINAPI SlowResponseServer(PVOID param) { | |
| 490 ServerEvents* events = reinterpret_cast<ServerEvents*>(param); | |
| 491 DWORD wait_result = 0; | |
| 492 wait_result = ::WaitForSingleObject(events->ping, INFINITE); | |
| 493 ::Sleep(kIPCWaitTimeOut1 + kIPCWaitTimeOut2 + 200); | |
| 494 ::InterlockedExchange(events->state, kAckChannel); | |
| 495 ::SetEvent(events->pong); | |
| 496 return wait_result; | |
| 497 } | |
| 498 | |
| 499 // This thread's job is to keep the mutex locked. | |
| 500 DWORD WINAPI MainServerThread(PVOID param) { | |
| 501 ServerEvents* events = reinterpret_cast<ServerEvents*>(param); | |
| 502 DWORD wait_result = 0; | |
| 503 wait_result = ::WaitForSingleObject(events->mutex, INFINITE); | |
| 504 Sleep(kIPCWaitTimeOut1 * 20); | |
| 505 return wait_result; | |
| 506 } | |
| 507 | |
| 508 // Creates a server thread that answers the IPC so slow that is guaranteed to | |
| 509 // trigger the time-out code path in the client. A second thread is created | |
| 510 // to hold locked the server_alive mutex: this signals the client that the | |
| 511 // server is not dead and it retries the wait. | |
| 512 TEST(IPCTest, ClientSlowServer) { | |
| 513 size_t base_start = 0; | |
| 514 IPCControl* client_control = | |
| 515 MakeChannels(kIPCChannelSize, 4096*2, &base_start); | |
| 516 FixChannels(client_control, base_start, kIPCChannelSize, FIX_PONG_NOT_READY); | |
| 517 client_control->server_alive = ::CreateMutex(NULL, FALSE, NULL); | |
| 518 | |
| 519 char* mem = reinterpret_cast<char*>(client_control); | |
| 520 SharedMemIPCClient client(mem); | |
| 521 | |
| 522 ServerEvents events = {0}; | |
| 523 events.ping = client_control->channels[0].ping_event; | |
| 524 events.pong = client_control->channels[0].pong_event; | |
| 525 events.state = &client_control->channels[0].state; | |
| 526 | |
| 527 HANDLE t1 = ::CreateThread(NULL, 0, SlowResponseServer, &events, 0, NULL); | |
| 528 ASSERT_TRUE(NULL != t1); | |
| 529 ::CloseHandle(t1); | |
| 530 | |
| 531 ServerEvents events2 = {0}; | |
| 532 events2.pong = events.pong; | |
| 533 events2.mutex = client_control->server_alive; | |
| 534 | |
| 535 HANDLE t2 = ::CreateThread(NULL, 0, MainServerThread, &events2, 0, NULL); | |
| 536 ASSERT_TRUE(NULL != t2); | |
| 537 ::CloseHandle(t2); | |
| 538 | |
| 539 ::Sleep(1); | |
| 540 | |
| 541 void* buff0 = client.GetBuffer(); | |
| 542 uint32 tag = 4321; | |
| 543 CrossCallReturn answer; | |
| 544 CrossCallParamsMock* params1 = new(buff0) CrossCallParamsMock(tag, 1); | |
| 545 FakeOkAnswerInChannel(buff0); | |
| 546 | |
| 547 ResultCode result = client.DoCall(params1, &answer); | |
| 548 if (SBOX_ERROR_CHANNEL_ERROR != result) | |
| 549 client.FreeBuffer(buff0); | |
| 550 | |
| 551 EXPECT_TRUE(SBOX_ALL_OK == result); | |
| 552 EXPECT_EQ(tag, client_control->channels[0].ipc_tag); | |
| 553 EXPECT_EQ(kFreeChannel, client_control->channels[0].state); | |
| 554 | |
| 555 CloseChannelEvents(client_control); | |
| 556 ::CloseHandle(client_control->server_alive); | |
| 557 delete[] reinterpret_cast<char*>(client_control); | |
| 558 } | |
| 559 | |
| 560 // This test-only IPC dispatcher has two handlers with the same signature | |
| 561 // but only CallOneHandler should be used. | |
| 562 class UnitTestIPCDispatcher : public Dispatcher { | |
| 563 public: | |
| 564 enum { | |
| 565 CALL_ONE_TAG = 78, | |
| 566 CALL_TWO_TAG = 87 | |
| 567 }; | |
| 568 | |
| 569 UnitTestIPCDispatcher(); | |
| 570 ~UnitTestIPCDispatcher() {}; | |
| 571 | |
| 572 virtual bool SetupService(InterceptionManager* manager, int service) { | |
| 573 return true; | |
| 574 } | |
| 575 | |
| 576 private: | |
| 577 bool CallOneHandler(IPCInfo* ipc, HANDLE p1, DWORD p2) { | |
| 578 ipc->return_info.extended[0].handle = p1; | |
| 579 ipc->return_info.extended[1].unsigned_int = p2; | |
| 580 return true; | |
| 581 } | |
| 582 | |
| 583 bool CallTwoHandler(IPCInfo* ipc, HANDLE p1, DWORD p2) { | |
| 584 return true; | |
| 585 } | |
| 586 }; | |
| 587 | |
| 588 UnitTestIPCDispatcher::UnitTestIPCDispatcher() { | |
| 589 static const IPCCall call_one = { | |
| 590 {CALL_ONE_TAG, VOIDPTR_TYPE, ULONG_TYPE}, | |
| 591 reinterpret_cast<CallbackGeneric>( | |
| 592 &UnitTestIPCDispatcher::CallOneHandler) | |
| 593 }; | |
| 594 static const IPCCall call_two = { | |
| 595 {CALL_TWO_TAG, VOIDPTR_TYPE, ULONG_TYPE}, | |
| 596 reinterpret_cast<CallbackGeneric>( | |
| 597 &UnitTestIPCDispatcher::CallTwoHandler) | |
| 598 }; | |
| 599 ipc_calls_.push_back(call_one); | |
| 600 ipc_calls_.push_back(call_two); | |
| 601 } | |
| 602 | |
| 603 // This test does most of the shared memory IPC client-server roundtrip | |
| 604 // and tests the packing, unpacking and call dispatching. | |
| 605 TEST(IPCTest, SharedMemServerTests) { | |
| 606 size_t base_start = 0; | |
| 607 IPCControl* client_control = | |
| 608 MakeChannels(kIPCChannelSize, 4096, &base_start); | |
| 609 client_control->server_alive = HANDLE(1); | |
| 610 FixChannels(client_control, base_start, kIPCChannelSize, FIX_PONG_READY); | |
| 611 | |
| 612 char* mem = reinterpret_cast<char*>(client_control); | |
| 613 SharedMemIPCClient client(mem); | |
| 614 | |
| 615 CrossCallReturn answer; | |
| 616 HANDLE bar = HANDLE(191919); | |
| 617 DWORD foo = 6767676; | |
| 618 CrossCall(client, UnitTestIPCDispatcher::CALL_ONE_TAG, bar, foo, &answer); | |
| 619 void* buff = client.GetBuffer(); | |
| 620 ASSERT_TRUE(NULL != buff); | |
| 621 | |
| 622 UnitTestIPCDispatcher dispatcher; | |
| 623 // Since we are directly calling InvokeCallback, most of this structure | |
| 624 // can be set to NULL. | |
| 625 sandbox::SharedMemIPCServer::ServerControl srv_control = { | |
| 626 NULL, NULL, kIPCChannelSize, NULL, | |
| 627 reinterpret_cast<char*>(client_control), | |
| 628 NULL, &dispatcher, {0} }; | |
| 629 | |
| 630 sandbox::CrossCallReturn call_return = {0}; | |
| 631 EXPECT_TRUE(SharedMemIPCServer::InvokeCallback(&srv_control, buff, | |
| 632 &call_return)); | |
| 633 EXPECT_EQ(SBOX_ALL_OK, call_return.call_outcome); | |
| 634 EXPECT_TRUE(bar == call_return.extended[0].handle); | |
| 635 EXPECT_EQ(foo, call_return.extended[1].unsigned_int); | |
| 636 | |
| 637 CloseChannelEvents(client_control); | |
| 638 delete[] reinterpret_cast<char*>(client_control); | |
| 639 } | |
| 640 | |
| 641 } // namespace sandbox | |
| OLD | NEW |