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 |