| OLD | NEW |
| (Empty) |
| 1 // Copyright 2015 The Crashpad Authors. All rights reserved. | |
| 2 // | |
| 3 // Licensed under the Apache License, Version 2.0 (the "License"); | |
| 4 // you may not use this file except in compliance with the License. | |
| 5 // You may obtain a copy of the License at | |
| 6 // | |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 | |
| 8 // | |
| 9 // Unless required by applicable law or agreed to in writing, software | |
| 10 // distributed under the License is distributed on an "AS IS" BASIS, | |
| 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 12 // See the License for the specific language governing permissions and | |
| 13 // limitations under the License. | |
| 14 | |
| 15 #include "handler/win/registration_server.h" | |
| 16 | |
| 17 #include <windows.h> | |
| 18 | |
| 19 #include <vector> | |
| 20 | |
| 21 #include "base/basictypes.h" | |
| 22 #include "base/strings/string16.h" | |
| 23 #include "client/crashpad_info.h" | |
| 24 #include "client/registration_protocol_win.h" | |
| 25 #include "gtest/gtest.h" | |
| 26 #include "handler/win/registration_test_base.h" | |
| 27 #include "util/thread/thread.h" | |
| 28 #include "util/win/address_types.h" | |
| 29 #include "util/win/scoped_handle.h" | |
| 30 | |
| 31 namespace crashpad { | |
| 32 namespace test { | |
| 33 namespace { | |
| 34 | |
| 35 // Runs the RegistrationServer on a background thread. | |
| 36 class RunServerThread : public Thread { | |
| 37 public: | |
| 38 // Instantiates a thread which will invoke server->Run(pipe_name, delegate). | |
| 39 RunServerThread(RegistrationServer* server, | |
| 40 const base::string16& pipe_name, | |
| 41 RegistrationServer::Delegate* delegate) | |
| 42 : server_(server), pipe_name_(pipe_name), delegate_(delegate) {} | |
| 43 ~RunServerThread() override {} | |
| 44 | |
| 45 private: | |
| 46 // Thread: | |
| 47 void ThreadMain() override { server_->Run(pipe_name_, delegate_); } | |
| 48 | |
| 49 RegistrationServer* server_; | |
| 50 base::string16 pipe_name_; | |
| 51 RegistrationServer::Delegate* delegate_; | |
| 52 | |
| 53 DISALLOW_COPY_AND_ASSIGN(RunServerThread); | |
| 54 }; | |
| 55 | |
| 56 class RegistrationServerTest : public RegistrationTestBase { | |
| 57 public: | |
| 58 RegistrationServerTest() | |
| 59 : server_(), server_thread_(&server_, pipe_name(), &delegate()) {} | |
| 60 | |
| 61 RegistrationServer& server() { return server_; } | |
| 62 Thread& server_thread() { return server_thread_; } | |
| 63 | |
| 64 private: | |
| 65 RegistrationServer server_; | |
| 66 RunServerThread server_thread_; | |
| 67 | |
| 68 DISALLOW_COPY_AND_ASSIGN(RegistrationServerTest); | |
| 69 }; | |
| 70 | |
| 71 // During destruction, ensures that the server is stopped and the background | |
| 72 // thread joined. | |
| 73 class ScopedStopServerAndJoinThread { | |
| 74 public: | |
| 75 explicit ScopedStopServerAndJoinThread(RegistrationServer* server, | |
| 76 Thread* thread) | |
| 77 : server_(server), thread_(thread) {} | |
| 78 ~ScopedStopServerAndJoinThread() { | |
| 79 server_->Stop(); | |
| 80 thread_->Join(); | |
| 81 } | |
| 82 | |
| 83 private: | |
| 84 RegistrationServer* server_; | |
| 85 Thread* thread_; | |
| 86 DISALLOW_COPY_AND_ASSIGN(ScopedStopServerAndJoinThread); | |
| 87 }; | |
| 88 | |
| 89 TEST_F(RegistrationServerTest, Instantiate) { | |
| 90 } | |
| 91 | |
| 92 TEST_F(RegistrationServerTest, StartAndStop) { | |
| 93 server_thread().Start(); | |
| 94 ScopedStopServerAndJoinThread scoped_stop_server_and_join_thread( | |
| 95 &server(), &server_thread()); | |
| 96 ASSERT_NO_FATAL_FAILURE(delegate().WaitForStart()); | |
| 97 } | |
| 98 | |
| 99 TEST_F(RegistrationServerTest, StopWhileConnected) { | |
| 100 ScopedFileHANDLE connection; | |
| 101 { | |
| 102 server_thread().Start(); | |
| 103 ScopedStopServerAndJoinThread scoped_stop_server_and_join_thread( | |
| 104 &server(), &server_thread()); | |
| 105 ASSERT_NO_FATAL_FAILURE(delegate().WaitForStart()); | |
| 106 connection = Connect(); | |
| 107 ASSERT_TRUE(connection.is_valid()); | |
| 108 // Leaving this scope causes the server to be stopped, while the connection | |
| 109 // is still open. | |
| 110 } | |
| 111 } | |
| 112 | |
| 113 TEST_F(RegistrationServerTest, Register) { | |
| 114 RegistrationRequest request = {0}; | |
| 115 RegistrationResponse response = {0}; | |
| 116 CrashpadInfo crashpad_info; | |
| 117 request.client_process_id = GetCurrentProcessId(); | |
| 118 request.crashpad_info_address = | |
| 119 reinterpret_cast<WinVMAddress>(&crashpad_info); | |
| 120 | |
| 121 server_thread().Start(); | |
| 122 ScopedStopServerAndJoinThread scoped_stop_server_and_join_thread( | |
| 123 &server(), &server_thread()); | |
| 124 | |
| 125 ASSERT_NO_FATAL_FAILURE(delegate().WaitForStart()); | |
| 126 | |
| 127 ASSERT_TRUE(SendRequest(Connect(), &request, sizeof(request), &response)); | |
| 128 | |
| 129 ASSERT_EQ(1, delegate().registered_processes().size()); | |
| 130 VerifyRegistration(*delegate().registered_processes()[0], request, response); | |
| 131 } | |
| 132 | |
| 133 TEST_F(RegistrationServerTest, ForgedClientId) { | |
| 134 // Skip this test on pre-Vista as the forged PID detection is not supported | |
| 135 // there. | |
| 136 OSVERSIONINFO vi = {0}; | |
| 137 vi.dwOSVersionInfoSize = sizeof(vi); | |
| 138 GetVersionEx(&vi); | |
| 139 if (vi.dwMajorVersion < 6) | |
| 140 return; | |
| 141 | |
| 142 RegistrationRequest request = {0}; | |
| 143 RegistrationResponse response = {0}; | |
| 144 CrashpadInfo crashpad_info; | |
| 145 // Note that we forge the PID here. | |
| 146 request.client_process_id = GetCurrentProcessId() + 1; | |
| 147 request.crashpad_info_address = | |
| 148 reinterpret_cast<WinVMAddress>(&crashpad_info); | |
| 149 | |
| 150 server_thread().Start(); | |
| 151 ScopedStopServerAndJoinThread scoped_stop_server_and_join_thread( | |
| 152 &server(), &server_thread()); | |
| 153 | |
| 154 ASSERT_NO_FATAL_FAILURE(delegate().WaitForStart()); | |
| 155 | |
| 156 ASSERT_FALSE(SendRequest(Connect(), &request, sizeof(request), &response)); | |
| 157 ASSERT_EQ(0, delegate().registered_processes().size()); | |
| 158 | |
| 159 // Correct the PID and verify that this was the only reason we failed. | |
| 160 request.client_process_id = GetCurrentProcessId(); | |
| 161 ASSERT_TRUE(SendRequest(Connect(), &request, sizeof(request), &response)); | |
| 162 ASSERT_EQ(1, delegate().registered_processes().size()); | |
| 163 VerifyRegistration(*delegate().registered_processes()[0], request, response); | |
| 164 } | |
| 165 | |
| 166 TEST_F(RegistrationServerTest, RegisterClientFails) { | |
| 167 RegistrationRequest request = {0}; | |
| 168 RegistrationResponse response = {0}; | |
| 169 CrashpadInfo crashpad_info; | |
| 170 request.client_process_id = GetCurrentProcessId(); | |
| 171 request.crashpad_info_address = | |
| 172 reinterpret_cast<WinVMAddress>(&crashpad_info); | |
| 173 | |
| 174 server_thread().Start(); | |
| 175 ScopedStopServerAndJoinThread scoped_stop_server_and_join_thread( | |
| 176 &server(), &server_thread()); | |
| 177 | |
| 178 ASSERT_NO_FATAL_FAILURE(delegate().WaitForStart()); | |
| 179 | |
| 180 // Simulate some failures | |
| 181 delegate().set_fail_mode(true); | |
| 182 for (int i = 0; i < 10; ++i) { | |
| 183 ASSERT_FALSE(SendRequest(Connect(), &request, sizeof(request), &response)); | |
| 184 ASSERT_EQ(0, delegate().registered_processes().size()); | |
| 185 } | |
| 186 | |
| 187 // Now verify that a valid response may still be processed. | |
| 188 delegate().set_fail_mode(false); | |
| 189 ASSERT_TRUE(SendRequest(Connect(), &request, sizeof(request), &response)); | |
| 190 | |
| 191 ASSERT_EQ(1, delegate().registered_processes().size()); | |
| 192 VerifyRegistration(*delegate().registered_processes()[0], request, response); | |
| 193 } | |
| 194 | |
| 195 TEST_F(RegistrationServerTest, BadRequests) { | |
| 196 server_thread().Start(); | |
| 197 ScopedStopServerAndJoinThread scoped_stop_server_and_join_thread( | |
| 198 &server(), &server_thread()); | |
| 199 ASSERT_NO_FATAL_FAILURE(delegate().WaitForStart()); | |
| 200 | |
| 201 RegistrationRequest request = {0}; | |
| 202 RegistrationResponse response = {0}; | |
| 203 CrashpadInfo crashpad_info; | |
| 204 request.client_process_id = GetCurrentProcessId(); | |
| 205 request.crashpad_info_address = | |
| 206 reinterpret_cast<WinVMAddress>(&crashpad_info); | |
| 207 | |
| 208 // Concatenate a valid request with a single byte of garbage. | |
| 209 std::vector<char> extra_long; | |
| 210 extra_long.insert(extra_long.begin(), | |
| 211 reinterpret_cast<char*>(&request), | |
| 212 reinterpret_cast<char*>(&request) + sizeof(request)); | |
| 213 extra_long.push_back('x'); | |
| 214 | |
| 215 for (int i = 0; i < 10; ++i) { | |
| 216 ASSERT_FALSE(SendRequest(Connect(), "a", 1, &response)); | |
| 217 ASSERT_FALSE(SendRequest( | |
| 218 Connect(), extra_long.data(), extra_long.size(), &response)); | |
| 219 ASSERT_TRUE(Connect().is_valid()); | |
| 220 } | |
| 221 | |
| 222 // Now verify that a valid response may still be processed. | |
| 223 | |
| 224 ASSERT_TRUE(SendRequest(Connect(), &request, sizeof(request), &response)); | |
| 225 | |
| 226 ASSERT_EQ(1, delegate().registered_processes().size()); | |
| 227 VerifyRegistration(*delegate().registered_processes()[0], request, response); | |
| 228 } | |
| 229 | |
| 230 TEST_F(RegistrationServerTest, OverlappingRequests) { | |
| 231 server_thread().Start(); | |
| 232 ScopedStopServerAndJoinThread scoped_stop_server_and_join_thread( | |
| 233 &server(), &server_thread()); | |
| 234 ASSERT_NO_FATAL_FAILURE(delegate().WaitForStart()); | |
| 235 | |
| 236 RegistrationRequest request = {0}; | |
| 237 RegistrationResponse response_1 = {0}; | |
| 238 RegistrationResponse response_2 = {0}; | |
| 239 RegistrationResponse response_3 = {0}; | |
| 240 CrashpadInfo crashpad_info; | |
| 241 request.client_process_id = GetCurrentProcessId(); | |
| 242 request.crashpad_info_address = | |
| 243 reinterpret_cast<WinVMAddress>(&crashpad_info); | |
| 244 | |
| 245 ScopedFileHANDLE connection_1 = Connect(); | |
| 246 ASSERT_TRUE(connection_1.is_valid()); | |
| 247 ScopedFileHANDLE connection_2 = Connect(); | |
| 248 ASSERT_TRUE(connection_2.is_valid()); | |
| 249 ScopedFileHANDLE connection_3 = Connect(); | |
| 250 ASSERT_TRUE(connection_3.is_valid()); | |
| 251 | |
| 252 ASSERT_FALSE(SendRequest(connection_1.Pass(), "a", 1, &response_1)); | |
| 253 | |
| 254 ASSERT_TRUE( | |
| 255 SendRequest(connection_2.Pass(), &request, sizeof(request), &response_2)); | |
| 256 | |
| 257 ASSERT_TRUE(Connect().is_valid()); | |
| 258 | |
| 259 ASSERT_TRUE( | |
| 260 SendRequest(connection_3.Pass(), &request, sizeof(request), &response_3)); | |
| 261 | |
| 262 ASSERT_EQ(2, delegate().registered_processes().size()); | |
| 263 VerifyRegistration( | |
| 264 *delegate().registered_processes()[0], request, response_2); | |
| 265 VerifyRegistration( | |
| 266 *delegate().registered_processes()[1], request, response_3); | |
| 267 } | |
| 268 | |
| 269 } // namespace | |
| 270 } // namespace test | |
| 271 } // namespace crashpad | |
| OLD | NEW |