Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1113)

Side by Side Diff: handler/win/registration_server_test.cc

Issue 1126783004: Introduce RegistrationServer. (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@master
Patch Set: Implement pipe client PID detection. Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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 <vector>
18
19 #include <windows.h>
scottmg 2015/05/20 18:53:10 C headers before C++ headers.
erikwright (departed) 2015/05/20 20:54:15 Done.
20 #include "base/basictypes.h"
scottmg 2015/05/20 18:53:10 Blank line before.
erikwright (departed) 2015/05/20 20:54:15 Acknowledged.
21 #include "base/memory/scoped_ptr.h"
scottmg 2015/05/20 18:53:10 unused?
erikwright (departed) 2015/05/20 20:54:15 Done.
22 #include "base/strings/string16.h"
23 #include "base/strings/stringprintf.h"
scottmg 2015/05/20 18:53:10 unused?
erikwright (departed) 2015/05/20 20:54:14 line 159
24 #include "base/strings/utf_string_conversions.h"
25 #include "client/crashpad_info.h"
26 #include "client/registration_protocol_win.h"
27 #include "gtest/gtest.h"
28 #include "util/stdlib/pointer_container.h"
scottmg 2015/05/20 18:53:10 unused?
erikwright (departed) 2015/05/20 20:54:15 used for PointerVector
scottmg 2015/05/21 02:32:36 I don't see a PointerVector in this file?
erikwright (departed) 2015/05/21 15:12:37 MockDelegate::registered_processes_
29 #include "util/thread/thread.h"
scottmg 2015/05/20 18:53:10 Looks like it could have stayed in test/ after all
erikwright (departed) 2015/05/20 20:54:15 Yeah, my initial implementation used this in Regis
30 #include "util/win/address_types.h"
31 #include "util/win/scoped_handle.h"
32
33 namespace crashpad {
34 namespace test {
35 namespace {
36
37 // Simulates a registrar to collect requests from and feed responses to the
38 // RegistrationServer.
39 class MockDelegate : public RegistrationServer::Delegate {
40 public:
41 // Records a single simulated client registration.
42 struct Entry {
43 Entry(ScopedKernelHANDLE client_process,
44 WinVMAddress crashpad_info_address,
45 HANDLE fake_request_dump_event,
46 HANDLE fake_dump_complete_event)
47 : client_process(client_process.Pass()),
48 crashpad_info_address(crashpad_info_address),
49 fake_request_dump_event_handle(fake_request_dump_event),
50 fake_dump_complete_event_handle(fake_dump_complete_event) {}
51
52 ScopedKernelHANDLE client_process;
53 WinVMAddress crashpad_info_address;
54 HANDLE fake_request_dump_event_handle;
55 HANDLE fake_dump_complete_event_handle;
56 };
57
58 MockDelegate()
59 : started_event_(CreateEvent(nullptr, TRUE, FALSE, nullptr)),
60 registered_processes_(),
61 next_fake_handle_(1),
62 fail_(false) {
63 EXPECT_TRUE(started_event_.is_valid());
64 }
65
66 ~MockDelegate() override {}
67
68 // Blocks until RegistrationServer::Delegate::OnStarted is invoked.
69 void WaitForStart() {
70 DWORD wait_result = WaitForSingleObject(started_event_.get(), INFINITE);
71 if (wait_result == WAIT_FAILED)
72 PLOG(ERROR);
73 ASSERT_EQ(wait_result, WAIT_OBJECT_0);
74 }
75
76 // RegistrationServer::Delegate:
77 void OnStarted() override { SetEvent(started_event_.get()); }
78
79 bool RegisterClient(ScopedKernelHANDLE client_process,
80 WinVMAddress crashpad_info_address,
81 HANDLE* request_dump_event,
82 HANDLE* dump_complete_event) override {
83 if (fail_)
84 return false;
85
86 if (!request_dump_event || !dump_complete_event) {
87 ADD_FAILURE() << "NULL 'out' parameter.";
88 return false;
89 }
90 *request_dump_event = reinterpret_cast<HANDLE>(next_fake_handle_++);
91 *dump_complete_event = reinterpret_cast<HANDLE>(next_fake_handle_++);
92
93 registered_processes_.push_back(new Entry(client_process.Pass(),
94 crashpad_info_address,
95 *request_dump_event,
96 *dump_complete_event));
97 return true;
98 }
99
100 // Provides access to the registered process data.
101 const std::vector<Entry*> registered_processes() {
102 return registered_processes_;
103 }
104
105 // If true, causes RegisterClient to simulate registration failure.
106 void set_fail_mode(bool fail) { fail_ = fail; }
107
108 private:
109 ScopedKernelHANDLE started_event_;
110 PointerVector<Entry> registered_processes_;
111 int next_fake_handle_;
112 bool fail_;
113
114 DISALLOW_COPY_AND_ASSIGN(MockDelegate);
115 };
116
117 // Verifies that the request and response match what was received and sent by
118 // the MockDelegate.
119 void VerifyRegistration(const MockDelegate::Entry& registered_process,
120 const RegistrationRequest& request,
121 const RegistrationResponse& response) {
122 EXPECT_EQ(request.crashpad_info_address,
123 registered_process.crashpad_info_address);
124 EXPECT_EQ(registered_process.fake_request_dump_event_handle,
125 response.request_report_event);
126 EXPECT_EQ(registered_process.fake_dump_complete_event_handle,
127 response.report_complete_event);
128 EXPECT_EQ(request.client_process_id,
129 GetProcessId(registered_process.client_process.get()));
130 }
131
132 // Runs the RegistrationServer on a background thread.
133 class RunServerThread : public Thread {
134 public:
135 // Instantiates a thread which will invoke server->Run(pipe_name, delegate).
136 RunServerThread(RegistrationServer* server,
137 const base::string16& pipe_name,
138 RegistrationServer::Delegate* delegate)
139 : server_(server), pipe_name_(pipe_name), delegate_(delegate) {}
140 ~RunServerThread() override {}
141
142 private:
143 // Thread :
scottmg 2015/05/20 18:53:10 no space before :
erikwright (departed) 2015/05/20 20:54:14 Done.
144 void ThreadMain() override { server_->Run(pipe_name_, delegate_); }
145
146 RegistrationServer* server_;
147 base::string16 pipe_name_;
148 RegistrationServer::Delegate* delegate_;
149
150 DISALLOW_COPY_AND_ASSIGN(RunServerThread);
151 };
152
153 class RegistrationServerTest : public testing::Test {
154 public:
155 RegistrationServerTest()
156 : server_(),
157 pipe_name_(L"\\\\.\\pipe\\registration_server_test_pipe_" +
158 base::UTF8ToUTF16(
159 base::StringPrintf("%08x", GetCurrentProcessId()))),
160 delegate_(),
161 server_thread_(&server_, pipe_name_, &delegate_) {}
162
163 RegistrationServer& server() { return server_; }
164 MockDelegate& delegate() { return delegate_; }
165 Thread& server_thread() { return server_thread_; }
166
167 // Returns a pipe handle connected to the RegistrationServer.
168 ScopedFileHANDLE Connect() {
169 ScopedFileHANDLE pipe;
170 const int kMaxRetries = 5;
171 for (int retries = 0; !pipe.is_valid() && retries < kMaxRetries; ++retries) {
scottmg 2015/05/20 18:53:10 80 col
erikwright (departed) 2015/05/20 20:54:15 Done.
172 if (!::WaitNamedPipe(pipe_name_.c_str(), NMPWAIT_WAIT_FOREVER))
scottmg 2015/05/20 18:53:10 No leading :: unless there's a name conflict (and
erikwright (departed) 2015/05/20 20:54:15 Done.
173 break;
174 pipe.reset(::CreateFile(pipe_name_.c_str(),
175 GENERIC_READ | GENERIC_WRITE,
176 0,
177 NULL,
178 OPEN_EXISTING,
179 SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION,
180 NULL));
181 }
182 EXPECT_TRUE(pipe.is_valid());
183 return pipe.Pass();
184 }
185
186 // Sends the provided request and receives a response via the provided pipe.
187 bool SendRequest(ScopedFileHANDLE pipe,
188 const void* request_buffer,
189 size_t request_size,
190 RegistrationResponse* response) {
191 DWORD mode = PIPE_READMODE_MESSAGE;
192 ::SetNamedPipeHandleState(pipe.get(), &mode, NULL, NULL);
193 DWORD bytes_read = 0;
194 if (::TransactNamedPipe(pipe.get(),
195 const_cast<void*>(request_buffer),
196 static_cast<DWORD>(request_size),
197 response,
198 sizeof(*response),
199 &bytes_read,
200 NULL)) {
201 if (bytes_read == sizeof(*response))
202 return true;
203 }
204 return false;
205 }
206
207 private:
208 RegistrationServer server_;
209 base::string16 pipe_name_;
210 MockDelegate delegate_;
211 RunServerThread server_thread_;
212
213 DISALLOW_COPY_AND_ASSIGN(RegistrationServerTest);
214 };
215
216 // During destruction, ensures that the server is stopped and the background
217 // thread joined.
218 class ScopedStopServerAndJoinThread {
219 public:
220 explicit ScopedStopServerAndJoinThread(RegistrationServer* server,
221 Thread* thread)
222 : server_(server), thread_(thread) {}
223 ~ScopedStopServerAndJoinThread() {
224 server_->Stop();
225 thread_->Join();
226 }
227
228 private:
229 RegistrationServer* server_;
230 Thread* thread_;
231 DISALLOW_COPY_AND_ASSIGN(ScopedStopServerAndJoinThread);
232 };
233
234 TEST_F(RegistrationServerTest, Instantiate) {
235 }
236
237 TEST_F(RegistrationServerTest, StartAndStop) {
238 server_thread().Start();
239 ScopedStopServerAndJoinThread scoped_stop_server_and_join_thread(
240 &server(), &server_thread());
241 ASSERT_NO_FATAL_FAILURE(delegate().WaitForStart());
242 }
243
244 TEST_F(RegistrationServerTest, StopWhileConnected) {
245 ScopedFileHANDLE connection;
246 {
247 server_thread().Start();
248 ScopedStopServerAndJoinThread scoped_stop_server_and_join_thread(
249 &server(), &server_thread());
250 ASSERT_NO_FATAL_FAILURE(delegate().WaitForStart());
251 connection = Connect();
252 ASSERT_TRUE(connection.is_valid());
253 // Leaving this scope causes the server to be stopped, while the connection
254 // is still open.
255 }
256 }
257
258 TEST_F(RegistrationServerTest, Register) {
259 RegistrationRequest request = {0};
260 RegistrationResponse response = {0};
261 CrashpadInfo crashpad_info;
262 request.client_process_id = GetCurrentProcessId();
263 request.crashpad_info_address =
264 reinterpret_cast<WinVMAddress>(&crashpad_info);
265
266 server_thread().Start();
267 ScopedStopServerAndJoinThread scoped_stop_server_and_join_thread(
268 &server(), &server_thread());
269
270 ASSERT_NO_FATAL_FAILURE(delegate().WaitForStart());
271
272 ASSERT_TRUE(SendRequest(Connect(), &request, sizeof(request), &response));
273
274 ASSERT_EQ(1, delegate().registered_processes().size());
275 VerifyRegistration(*delegate().registered_processes()[0], request, response);
276 }
277
278 TEST_F(RegistrationServerTest, ForgedClientId) {
279 // Skip this test on pre-Vista as the forged PID detection is not supported
280 // there.
281 OSVERSIONINFO vi = {0};
282 vi.dwOSVersionInfoSize = sizeof(vi);
283 GetVersionEx(&vi);
284 if (vi.dwMajorVersion < 6)
285 return;
286
287 RegistrationRequest request = {0};
288 RegistrationResponse response = {0};
289 CrashpadInfo crashpad_info;
290 // Note that we forge the PID here.
291 request.client_process_id = GetCurrentProcessId() + 1;
292 request.crashpad_info_address =
293 reinterpret_cast<WinVMAddress>(&crashpad_info);
294
295 server_thread().Start();
296 ScopedStopServerAndJoinThread scoped_stop_server_and_join_thread(
297 &server(), &server_thread());
298
299 ASSERT_NO_FATAL_FAILURE(delegate().WaitForStart());
300
301 ASSERT_FALSE(SendRequest(Connect(), &request, sizeof(request), &response));
302 ASSERT_EQ(0, delegate().registered_processes().size());
303
304 // Correct the PID and verify that this was the only reason we failed.
305 request.client_process_id = GetCurrentProcessId();
306 ASSERT_TRUE(SendRequest(Connect(), &request, sizeof(request), &response));
307 ASSERT_EQ(1, delegate().registered_processes().size());
308 VerifyRegistration(*delegate().registered_processes()[0], request, response);
309 }
310
311 TEST_F(RegistrationServerTest, RegisterClientFails) {
312 RegistrationRequest request = {0};
313 RegistrationResponse response = {0};
314 CrashpadInfo crashpad_info;
315 request.client_process_id = GetCurrentProcessId();
316 request.crashpad_info_address =
317 reinterpret_cast<WinVMAddress>(&crashpad_info);
318
319 server_thread().Start();
320 ScopedStopServerAndJoinThread scoped_stop_server_and_join_thread(
321 &server(), &server_thread());
322
323 ASSERT_NO_FATAL_FAILURE(delegate().WaitForStart());
324
325 // Simulate some failures
326 delegate().set_fail_mode(true);
327 for (int i = 0; i < 10; ++i) {
328 ASSERT_FALSE(SendRequest(Connect(), &request, sizeof(request), &response));
329 ASSERT_EQ(0, delegate().registered_processes().size());
330 }
331
332 // Now verify that a valid response may still be processed.
333 delegate().set_fail_mode(false);
334 ASSERT_TRUE(SendRequest(Connect(), &request, sizeof(request), &response));
335
336 ASSERT_EQ(1, delegate().registered_processes().size());
337 VerifyRegistration(*delegate().registered_processes()[0], request, response);
338 }
339
340 TEST_F(RegistrationServerTest, BadRequests) {
341 server_thread().Start();
342 ScopedStopServerAndJoinThread scoped_stop_server_and_join_thread(
343 &server(), &server_thread());
344 ASSERT_NO_FATAL_FAILURE(delegate().WaitForStart());
345
346 RegistrationRequest request = {0};
347 RegistrationResponse response = {0};
348 CrashpadInfo crashpad_info;
349 request.client_process_id = GetCurrentProcessId();
350 request.crashpad_info_address =
351 reinterpret_cast<WinVMAddress>(&crashpad_info);
352
353 // Concatenate a valid request with a single byte of garbage.
354 std::vector<char> extra_long;
355 extra_long.insert(extra_long.begin(),
356 reinterpret_cast<char*>(&request),
357 reinterpret_cast<char*>(&request) + sizeof(request));
358 extra_long.push_back('x');
359
360 for (int i = 0; i < 10; ++i) {
361 ASSERT_FALSE(SendRequest(Connect(), "a", 1, &response));
362 ASSERT_FALSE(SendRequest(
363 Connect(), extra_long.data(), extra_long.size(), &response));
364 ASSERT_TRUE(Connect().is_valid());
365 }
366
367 // Now verify that a valid response may still be processed.
368
369 ASSERT_TRUE(SendRequest(Connect(), &request, sizeof(request), &response));
370
371 ASSERT_EQ(1, delegate().registered_processes().size());
372 VerifyRegistration(*delegate().registered_processes()[0], request, response);
373 }
374
375 TEST_F(RegistrationServerTest, OverlappingRequests) {
376 server_thread().Start();
377 ScopedStopServerAndJoinThread scoped_stop_server_and_join_thread(
378 &server(), &server_thread());
379 ASSERT_NO_FATAL_FAILURE(delegate().WaitForStart());
380
381 RegistrationRequest request = {0};
382 RegistrationResponse response_1 = {0};
383 RegistrationResponse response_2 = {0};
384 RegistrationResponse response_3 = {0};
385 CrashpadInfo crashpad_info;
386 request.client_process_id = GetCurrentProcessId();
387 request.crashpad_info_address =
388 reinterpret_cast<WinVMAddress>(&crashpad_info);
389
390 ScopedFileHANDLE connection_1 = Connect();
391 ASSERT_TRUE(connection_1.is_valid());
392 ScopedFileHANDLE connection_2 = Connect();
393 ASSERT_TRUE(connection_2.is_valid());
394 ScopedFileHANDLE connection_3 = Connect();
395 ASSERT_TRUE(connection_3.is_valid());
396
397 ASSERT_FALSE(SendRequest(connection_1.Pass(), "a", 1, &response_1));
398
399 ASSERT_TRUE(
400 SendRequest(connection_2.Pass(), &request, sizeof(request), &response_2));
401
402 ASSERT_TRUE(Connect().is_valid());
403
404 ASSERT_TRUE(
405 SendRequest(connection_3.Pass(), &request, sizeof(request), &response_3));
406
407 ASSERT_EQ(2, delegate().registered_processes().size());
408 VerifyRegistration(*delegate().registered_processes()[0], request, response_2) ;
scottmg 2015/05/20 18:53:10 80 col
erikwright (departed) 2015/05/20 20:54:15 Done.
409 VerifyRegistration(*delegate().registered_processes()[1], request, response_3) ;
410 }
411
412 } // namespace
413 } // namespace test
414 } // namespace crashpad
OLDNEW
« handler/win/registration_server.cc ('K') | « handler/win/registration_server.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698