Index: sandbox/src/ipc_unittest.cc |
=================================================================== |
--- sandbox/src/ipc_unittest.cc (revision 41493) |
+++ sandbox/src/ipc_unittest.cc (working copy) |
@@ -6,9 +6,9 @@ |
#include "sandbox/src/crosscall_client.h" |
#include "sandbox/src/crosscall_server.h" |
#include "sandbox/src/sharedmem_ipc_client.h" |
+#include "sandbox/src/sharedmem_ipc_server.h" |
#include "testing/gtest/include/gtest/gtest.h" |
- |
namespace sandbox { |
// Helper function to make the fake shared memory with some |
@@ -18,30 +18,54 @@ |
// Allocate memory |
char* mem = new char[total_shared_size]; |
memset(mem, 0, total_shared_size); |
- |
// Calculate how many channels we can fit in the shared memory. |
total_shared_size -= offsetof(IPCControl, channels); |
size_t channel_count = |
total_shared_size / (sizeof(ChannelControl) + channel_size); |
- |
// Calculate the start of the first channel. |
*base_start = (sizeof(ChannelControl)* channel_count) + |
offsetof(IPCControl, channels); |
- |
// Setup client structure. |
IPCControl* client_control = reinterpret_cast<IPCControl*>(mem); |
client_control->channels_count = channel_count; |
- |
return client_control; |
} |
+enum TestFixMode { |
+ FIX_NO_EVENTS, |
+ FIX_PONG_READY, |
+ FIX_PONG_NOT_READY |
+}; |
+ |
+void FixChannels(IPCControl* client_control, size_t base_start, |
+ size_t channel_size, TestFixMode mode) { |
+ for (size_t ix = 0; ix != client_control->channels_count; ++ix) { |
+ ChannelControl& channel = client_control->channels[ix]; |
+ channel.channel_base = base_start; |
+ channel.state = kFreeChannel; |
+ if (mode != FIX_NO_EVENTS) { |
+ BOOL signaled = (FIX_PONG_READY == mode)? TRUE : FALSE; |
+ channel.ping_event = ::CreateEventW(NULL, FALSE, FALSE, NULL); |
+ channel.pong_event = ::CreateEventW(NULL, FALSE, signaled, NULL); |
+ } |
+ base_start += channel_size; |
+ } |
+} |
+ |
+void CloseChannelEvents(IPCControl* client_control) { |
+ for (size_t ix = 0; ix != client_control->channels_count; ++ix) { |
+ ChannelControl& channel = client_control->channels[ix]; |
+ ::CloseHandle(channel.ping_event); |
+ ::CloseHandle(channel.pong_event); |
+ } |
+} |
+ |
TEST(IPCTest, ChannelMaker) { |
- size_t channel_start = 0; |
- IPCControl* client_control = MakeChannels(12*64, 4096, &channel_start); |
- |
// Test that our testing rig is computing offsets properly. We should have |
// 5 channnels and the offset to the first channel is 108 bytes in 32 bits |
// and 216 in 64 bits. |
+ size_t channel_start = 0; |
+ IPCControl* client_control = MakeChannels(12 * 64, 4096, &channel_start); |
ASSERT_TRUE(NULL != client_control); |
EXPECT_EQ(5, client_control->channels_count); |
#if defined(_WIN64) |
@@ -49,24 +73,17 @@ |
#else |
EXPECT_EQ(108, channel_start); |
#endif |
- |
- delete [] reinterpret_cast<char*>(client_control); |
+ delete[] reinterpret_cast<char*>(client_control); |
} |
TEST(IPCTest, ClientLockUnlock) { |
// Make 7 channels of kIPCChannelSize (1kb) each. Test that we lock and |
// unlock channels properly. |
- const size_t channel_size = kIPCChannelSize; |
size_t base_start = 0; |
- IPCControl* client_control = MakeChannels(channel_size, 4096*2, &base_start); |
+ IPCControl* client_control = |
+ MakeChannels(kIPCChannelSize, 4096 * 2, &base_start); |
+ FixChannels(client_control, base_start, kIPCChannelSize, FIX_NO_EVENTS); |
- for (size_t ix = 0; ix != client_control->channels_count; ++ix) { |
- ChannelControl& channel = client_control->channels[ix]; |
- channel.channel_base = base_start; |
- channel.state = kFreeChannel; |
- base_start += channel_size; |
- } |
- |
char* mem = reinterpret_cast<char*>(client_control); |
SharedMemIPCClient client(mem); |
@@ -124,27 +141,19 @@ |
EXPECT_EQ(kFreeChannel, client_control->channels[4].state); |
EXPECT_EQ(kFreeChannel, client_control->channels[5].state); |
- delete [] reinterpret_cast<char*>(client_control); |
+ delete[] reinterpret_cast<char*>(client_control); |
} |
TEST(IPCTest, CrossCallStrPacking) { |
// This test tries the CrossCall object with null and non-null string |
- // combination of parameters and verifies that the unpacker can read them |
- // properly. |
- const size_t channel_size = kIPCChannelSize; |
+ // combination of parameters, integer types and verifies that the unpacker |
+ // can read them properly. |
size_t base_start = 0; |
- IPCControl* client_control = MakeChannels(channel_size, 4096*2, &base_start); |
+ IPCControl* client_control = |
+ MakeChannels(kIPCChannelSize, 4096 * 4, &base_start); |
client_control->server_alive = HANDLE(1); |
+ FixChannels(client_control, base_start, kIPCChannelSize, FIX_PONG_READY); |
- for (size_t ix = 0; ix != client_control->channels_count; ++ix) { |
- ChannelControl& channel = client_control->channels[ix]; |
- channel.channel_base = base_start; |
- channel.state = kFreeChannel; |
- channel.ping_event = ::CreateEventW(NULL, FALSE, FALSE, NULL); |
- channel.pong_event = ::CreateEventW(NULL, FALSE, TRUE, NULL); |
- base_start += channel_size; |
- } |
- |
char* mem = reinterpret_cast<char*>(client_control); |
SharedMemIPCClient client(mem); |
@@ -212,14 +221,81 @@ |
EXPECT_EQ(0, param_size); |
EXPECT_EQ(WCHAR_TYPE, type); |
- for (size_t ix = 0; ix != client_control->channels_count; ++ix) { |
- ChannelControl& channel = client_control->channels[ix]; |
- ::CloseHandle(channel.ping_event); |
- ::CloseHandle(channel.pong_event); |
- } |
- delete [] reinterpret_cast<char*>(client_control); |
+ CloseChannelEvents(client_control); |
+ delete[] reinterpret_cast<char*>(client_control); |
} |
+TEST(IPCTest, CrossCallIntPacking) { |
+ // Check handling for regular 32 bit integers used in Windows. |
+ size_t base_start = 0; |
+ IPCControl* client_control = |
+ MakeChannels(kIPCChannelSize, 4096 * 4, &base_start); |
+ client_control->server_alive = HANDLE(1); |
+ FixChannels(client_control, base_start, kIPCChannelSize, FIX_PONG_READY); |
+ |
+ uint32 tag1 = 999; |
+ uint32 tag2 = 111; |
+ const wchar_t text[] = L"godzilla"; |
+ CrossCallParamsEx* actual_params; |
+ |
+ char* mem = reinterpret_cast<char*>(client_control); |
+ SharedMemIPCClient client(mem); |
+ |
+ CrossCallReturn answer; |
+ DWORD dw = 0xE6578; |
+ CrossCall(client, tag2, dw, &answer); |
+ actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer()); |
+ EXPECT_EQ(1, actual_params->GetParamsCount()); |
+ EXPECT_EQ(tag2, actual_params->GetTag()); |
+ ArgType type = INVALID_TYPE; |
+ size_t param_size = 1; |
+ void* param_addr = actual_params->GetRawParameter(0, ¶m_size, &type); |
+ ASSERT_EQ(sizeof(dw), param_size); |
+ EXPECT_EQ(ULONG_TYPE, type); |
+ ASSERT_TRUE(NULL != param_addr); |
+ EXPECT_EQ(0, memcmp(&dw, param_addr, param_size)); |
+ |
+ // Check handling for windows HANDLES. |
+ HANDLE h = HANDLE(0x70000500); |
+ CrossCall(client, tag1, text, h, &answer); |
+ actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer()); |
+ EXPECT_EQ(2, actual_params->GetParamsCount()); |
+ EXPECT_EQ(tag1, actual_params->GetTag()); |
+ type = INVALID_TYPE; |
+ param_addr = actual_params->GetRawParameter(1, ¶m_size, &type); |
+ ASSERT_EQ(sizeof(h), param_size); |
+ EXPECT_EQ(VOIDPTR_TYPE, type); |
+ ASSERT_TRUE(NULL != param_addr); |
+ EXPECT_EQ(0, memcmp(&h, param_addr, param_size)); |
+ |
+ // Check combination of 32 and 64 bits. |
+ CrossCall(client, tag2, h, dw, h, &answer); |
+ actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer()); |
+ EXPECT_EQ(3, actual_params->GetParamsCount()); |
+ EXPECT_EQ(tag2, actual_params->GetTag()); |
+ type = INVALID_TYPE; |
+ param_addr = actual_params->GetRawParameter(0, ¶m_size, &type); |
+ ASSERT_EQ(sizeof(h), param_size); |
+ EXPECT_EQ(VOIDPTR_TYPE, type); |
+ ASSERT_TRUE(NULL != param_addr); |
+ EXPECT_EQ(0, memcmp(&h, param_addr, param_size)); |
+ type = INVALID_TYPE; |
+ param_addr = actual_params->GetRawParameter(1, ¶m_size, &type); |
+ ASSERT_EQ(sizeof(dw), param_size); |
+ EXPECT_EQ(ULONG_TYPE, type); |
+ ASSERT_TRUE(NULL != param_addr); |
+ EXPECT_EQ(0, memcmp(&dw, param_addr, param_size)); |
+ type = INVALID_TYPE; |
+ param_addr = actual_params->GetRawParameter(2, ¶m_size, &type); |
+ ASSERT_EQ(sizeof(h), param_size); |
+ EXPECT_EQ(VOIDPTR_TYPE, type); |
+ ASSERT_TRUE(NULL != param_addr); |
+ EXPECT_EQ(0, memcmp(&h, param_addr, param_size)); |
+ |
+ CloseChannelEvents(client_control); |
+ delete[] reinterpret_cast<char*>(client_control); |
+} |
+ |
TEST(IPCTest, CrossCallValidation) { |
// First a sanity test with a well formed parameter object. |
unsigned long value = 124816; |
@@ -297,17 +373,9 @@ |
TEST(IPCTest, ClientFastServer) { |
const size_t channel_size = kIPCChannelSize; |
size_t base_start = 0; |
- IPCControl* client_control = MakeChannels(channel_size, 4096*2, &base_start); |
- |
- for (size_t ix = 0; ix != client_control->channels_count; ++ix) { |
- ChannelControl& channel = client_control->channels[ix]; |
- channel.channel_base = base_start; |
- channel.state = kFreeChannel; |
- channel.ping_event = ::CreateEventW(NULL, FALSE, FALSE, NULL); |
- channel.pong_event = ::CreateEventW(NULL, FALSE, FALSE, NULL); |
- base_start += channel_size; |
- } |
- |
+ IPCControl* client_control = |
+ MakeChannels(channel_size, 4096 * 2, &base_start); |
+ FixChannels(client_control, base_start, kIPCChannelSize, FIX_PONG_NOT_READY); |
client_control->server_alive = ::CreateMutex(NULL, FALSE, NULL); |
char* mem = reinterpret_cast<char*>(client_control); |
@@ -374,14 +442,10 @@ |
EXPECT_EQ(kFreeChannel, client_control->channels[1].state); |
EXPECT_EQ(kFreeChannel, client_control->channels[2].state); |
- for (size_t ix = 0; ix != client_control->channels_count; ++ix) { |
- ChannelControl& channel = client_control->channels[ix]; |
- ::CloseHandle(channel.ping_event); |
- ::CloseHandle(channel.pong_event); |
- } |
+ CloseChannelEvents(client_control); |
+ ::CloseHandle(client_control->server_alive); |
- ::CloseHandle(client_control->server_alive); |
- delete [] reinterpret_cast<char*>(client_control); |
+ delete[] reinterpret_cast<char*>(client_control); |
} |
// This is the server thread that very slowly answers an IPC and exits. Note |
@@ -410,19 +474,10 @@ |
// to hold locked the server_alive mutex: this signals the client that the |
// server is not dead and it retries the wait. |
TEST(IPCTest, ClientSlowServer) { |
- const size_t channel_size = kIPCChannelSize; |
size_t base_start = 0; |
- IPCControl* client_control = MakeChannels(channel_size, 4096*2, &base_start); |
- |
- for (size_t ix = 0; ix != client_control->channels_count; ++ix) { |
- ChannelControl& channel = client_control->channels[ix]; |
- channel.channel_base = base_start; |
- channel.state = kFreeChannel; |
- channel.ping_event = ::CreateEventW(NULL, FALSE, FALSE, NULL); |
- channel.pong_event = ::CreateEventW(NULL, FALSE, FALSE, NULL); |
- base_start += channel_size; |
- } |
- |
+ IPCControl* client_control = |
+ MakeChannels(kIPCChannelSize, 4096*2, &base_start); |
+ FixChannels(client_control, base_start, kIPCChannelSize, FIX_PONG_NOT_READY); |
client_control->server_alive = ::CreateMutex(NULL, FALSE, NULL); |
char* mem = reinterpret_cast<char*>(client_control); |
@@ -461,13 +516,90 @@ |
EXPECT_EQ(tag, client_control->channels[0].ipc_tag); |
EXPECT_EQ(kFreeChannel, client_control->channels[0].state); |
- for (size_t ix = 0; ix != client_control->channels_count; ++ix) { |
- ChannelControl& channel = client_control->channels[ix]; |
- ::CloseHandle(channel.ping_event); |
- ::CloseHandle(channel.pong_event); |
- } |
+ CloseChannelEvents(client_control); |
::CloseHandle(client_control->server_alive); |
- delete [] reinterpret_cast<char*>(client_control); |
+ delete[] reinterpret_cast<char*>(client_control); |
} |
+// This test-only IPC dispatcher has two handlers with the same signature |
+// but only CallOneHandler should be used. |
+class UnitTestIPCDispatcher : public Dispatcher { |
+ public: |
+ enum { |
+ CALL_ONE_TAG = 78, |
+ CALL_TWO_TAG = 87 |
+ }; |
+ |
+ UnitTestIPCDispatcher(); |
+ ~UnitTestIPCDispatcher() {}; |
+ |
+ virtual bool SetupService(InterceptionManager* manager, int service) { |
+ return true; |
+ } |
+ |
+ private: |
+ bool CallOneHandler(IPCInfo* ipc, HANDLE p1, DWORD p2) { |
+ ipc->return_info.extended[0].handle = p1; |
+ ipc->return_info.extended[1].unsigned_int = p2; |
+ return true; |
+ } |
+ |
+ bool CallTwoHandler(IPCInfo* ipc, HANDLE p1, DWORD p2) { |
+ return true; |
+ } |
+}; |
+ |
+UnitTestIPCDispatcher::UnitTestIPCDispatcher() { |
+ static const IPCCall call_one = { |
+ {CALL_ONE_TAG, VOIDPTR_TYPE, ULONG_TYPE}, |
+ reinterpret_cast<CallbackGeneric>( |
+ &UnitTestIPCDispatcher::CallOneHandler) |
+ }; |
+ static const IPCCall call_two = { |
+ {CALL_TWO_TAG, VOIDPTR_TYPE, ULONG_TYPE}, |
+ reinterpret_cast<CallbackGeneric>( |
+ &UnitTestIPCDispatcher::CallTwoHandler) |
+ }; |
+ ipc_calls_.push_back(call_one); |
+ ipc_calls_.push_back(call_two); |
+} |
+ |
+// This test does most of the shared memory IPC client-server roundtrip |
+// and tests the packing, unpacking and call dispatching. |
+TEST(IPCTest, SharedMemServerTests) { |
+ size_t base_start = 0; |
+ IPCControl* client_control = |
+ MakeChannels(kIPCChannelSize, 4096, &base_start); |
+ client_control->server_alive = HANDLE(1); |
+ FixChannels(client_control, base_start, kIPCChannelSize, FIX_PONG_READY); |
+ |
+ char* mem = reinterpret_cast<char*>(client_control); |
+ SharedMemIPCClient client(mem); |
+ |
+ CrossCallReturn answer; |
+ HANDLE bar = HANDLE(191919); |
+ DWORD foo = 6767676; |
+ CrossCall(client, UnitTestIPCDispatcher::CALL_ONE_TAG, bar, foo, &answer); |
+ void* buff = client.GetBuffer(); |
+ ASSERT_TRUE(NULL != buff); |
+ |
+ UnitTestIPCDispatcher dispatcher; |
+ // Since we are directly calling InvokeCallback, most of this structure |
+ // can be set to NULL. |
+ sandbox::SharedMemIPCServer::ServerControl srv_control = { |
+ NULL, NULL, kIPCChannelSize, NULL, |
+ reinterpret_cast<char*>(client_control), |
+ NULL, &dispatcher, {0} }; |
+ |
+ sandbox::CrossCallReturn call_return = {0}; |
+ EXPECT_TRUE(SharedMemIPCServer::InvokeCallback(&srv_control, buff, |
+ &call_return)); |
+ EXPECT_EQ(SBOX_ALL_OK, call_return.call_outcome); |
+ EXPECT_TRUE(bar == call_return.extended[0].handle); |
+ EXPECT_EQ(foo, call_return.extended[1].unsigned_int); |
+ |
+ CloseChannelEvents(client_control); |
+ delete[] reinterpret_cast<char*>(client_control); |
+} |
+ |
} // namespace sandbox |