Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(60)

Side by Side Diff: src/client/windows/crash_generation/crash_generation_server.cc

Issue 196001: Fix CrashGenerationServer to recover from protocol errors and a test for same. (Closed) Base URL: http://google-breakpad.googlecode.com/svn/trunk/
Patch Set: Created 14 years, 6 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2008, Google Inc. 1 // Copyright (c) 2008, Google Inc.
2 // All rights reserved. 2 // All rights reserved.
3 // 3 //
4 // Redistribution and use in source and binary forms, with or without 4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are 5 // modification, are permitted provided that the following conditions are
6 // met: 6 // met:
7 // 7 //
8 // * Redistributions of source code must retain the above copyright 8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer. 9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above 10 // * Redistributions in binary form must reproduce the above
(...skipping 16 matching lines...) Expand all
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 29
30 #include "client/windows/crash_generation/crash_generation_server.h" 30 #include "client/windows/crash_generation/crash_generation_server.h"
31 #include <windows.h> 31 #include <windows.h>
32 #include <cassert> 32 #include <cassert>
33 #include <list> 33 #include <list>
34 #include "client/windows/common/auto_critical_section.h" 34 #include "client/windows/common/auto_critical_section.h"
35 #include "processor/scoped_ptr.h" 35 #include "processor/scoped_ptr.h"
36 36
37 #include "client/windows/crash_generation/client_info.h"
Erik Wright 2010/09/16 21:06:59 Changed to a forward-decl in crash_generation_serv
38
37 namespace google_breakpad { 39 namespace google_breakpad {
38 40
41 // How long to wait for the server thread to begin listening or die trying
42 static const DWORD kMaxStartDelayMs = INFINITE;
43
39 // Output buffer size. 44 // Output buffer size.
40 static const size_t kOutBufferSize = 64; 45 static const size_t kOutBufferSize = 64;
41 46
42 // Input buffer size. 47 // Input buffer size.
43 static const size_t kInBufferSize = 64; 48 static const size_t kInBufferSize = 64;
44 49
45 // Access flags for the client on the dump request event. 50 // Access flags for the client on the dump request event.
46 static const DWORD kDumpRequestEventAccess = EVENT_MODIFY_STATE; 51 static const DWORD kDumpRequestEventAccess = EVENT_MODIFY_STATE;
47 52
48 // Access flags for the client on the dump generated event. 53 // Access flags for the client on the dump generated event.
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
110 dump_callback_(dump_callback), 115 dump_callback_(dump_callback),
111 dump_context_(dump_context), 116 dump_context_(dump_context),
112 exit_callback_(exit_callback), 117 exit_callback_(exit_callback),
113 exit_context_(exit_context), 118 exit_context_(exit_context),
114 generate_dumps_(generate_dumps), 119 generate_dumps_(generate_dumps),
115 dump_generator_(NULL), 120 dump_generator_(NULL),
116 server_state_(IPC_SERVER_STATE_INITIAL), 121 server_state_(IPC_SERVER_STATE_INITIAL),
117 shutting_down_(false), 122 shutting_down_(false),
118 overlapped_(), 123 overlapped_(),
119 client_info_(NULL), 124 client_info_(NULL),
120 cleanup_item_count_(0) { 125 cleanup_item_count_(0),
126 server_start_complete_event_(NULL) {
121 InitializeCriticalSection(&clients_sync_); 127 InitializeCriticalSection(&clients_sync_);
122 128
123 if (dump_path) { 129 if (dump_path) {
124 dump_generator_.reset(new MinidumpGenerator(*dump_path)); 130 dump_generator_.reset(new MinidumpGenerator(*dump_path));
125 } 131 }
126 } 132 }
127 133
128 CrashGenerationServer::~CrashGenerationServer() { 134 CrashGenerationServer::~CrashGenerationServer() {
129 // Indicate to existing threads that server is shutting down. 135 // Indicate to existing threads that server is shutting down.
130 shutting_down_ = true; 136 shutting_down_ = true;
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
193 if (server_alive_handle_) { 199 if (server_alive_handle_) {
194 // Release the mutex before closing the handle so that clients requesting 200 // Release the mutex before closing the handle so that clients requesting
195 // dumps wait for a long time for the server to generate a dump. 201 // dumps wait for a long time for the server to generate a dump.
196 ReleaseMutex(server_alive_handle_); 202 ReleaseMutex(server_alive_handle_);
197 CloseHandle(server_alive_handle_); 203 CloseHandle(server_alive_handle_);
198 } 204 }
199 205
200 DeleteCriticalSection(&clients_sync_); 206 DeleteCriticalSection(&clients_sync_);
201 } 207 }
202 208
203 bool CrashGenerationServer::Start() { 209 bool CrashGenerationServer::Start() {
Erik Wright 2010/09/16 21:06:59 A non-negligible change in this function's behavio
204 server_state_ = IPC_SERVER_STATE_INITIAL; 210 server_state_ = IPC_SERVER_STATE_INITIAL;
205 211
212 server_start_complete_event_ = CreateEvent(NULL, TRUE, FALSE, NULL);
213 if (!server_start_complete_event_) {
214 return false;
215 }
216
206 server_alive_handle_ = CreateMutex(NULL, TRUE, NULL); 217 server_alive_handle_ = CreateMutex(NULL, TRUE, NULL);
207 if (!server_alive_handle_) { 218 if (!server_alive_handle_) {
208 return false; 219 return false;
209 } 220 }
210 221
211 // Event to signal the client connection and pipe reads and writes. 222 // Event to signal the client connection and pipe reads and writes.
212 overlapped_.hEvent = CreateEvent(NULL, // Security descriptor. 223 overlapped_.hEvent = CreateEvent(NULL, // Security descriptor.
213 TRUE, // Manual reset. 224 TRUE, // Manual reset.
214 FALSE, // Initially signaled. 225 FALSE, // Initially signaled.
215 NULL); // Name. 226 NULL); // Name.
(...skipping 18 matching lines...) Expand all
234 kOutBufferSize, 245 kOutBufferSize,
235 kInBufferSize, 246 kInBufferSize,
236 0, 247 0,
237 pipe_sec_attrs_); 248 pipe_sec_attrs_);
238 if (pipe_ == INVALID_HANDLE_VALUE) { 249 if (pipe_ == INVALID_HANDLE_VALUE) {
239 return false; 250 return false;
240 } 251 }
241 252
242 // Signal the event to start a separate thread to handle 253 // Signal the event to start a separate thread to handle
243 // client connections. 254 // client connections.
244 return SetEvent(overlapped_.hEvent) != FALSE; 255 if (SetEvent(overlapped_.hEvent) == FALSE) {
256 return false;
257 }
258
259 if (WaitForSingleObject(server_start_complete_event_, kMaxStartDelayMs) !=
Erik Wright 2010/09/16 21:06:59 I don't think it is possible for the worker thread
260 WAIT_OBJECT_0) {
261 return false;
262 }
263
264 // If we are in error state, it's probably because we failed to start,
265 // though it could theoretically be due to a failure between succesful start
266 // and our return from the above wait.
267 return server_state_ != IPC_SERVER_STATE_ERROR;
245 } 268 }
246 269
247 // If the server thread serving clients ever gets into the 270 // If the server thread serving clients ever gets into the
248 // ERROR state, reset the event, close the pipe and remain 271 // ERROR state, reset the event, close the pipe and remain
249 // in the error state forever. Error state means something 272 // in the error state forever. Error state means something
250 // that we didn't account for has happened, and it's dangerous 273 // that we didn't account for has happened, and it's dangerous
251 // to do anything unknowingly. 274 // to do anything unknowingly.
252 void CrashGenerationServer::HandleErrorState() { 275 void CrashGenerationServer::HandleErrorState() {
253 assert(server_state_ == IPC_SERVER_STATE_ERROR); 276 assert(server_state_ == IPC_SERVER_STATE_ERROR);
254 277
(...skipping 21 matching lines...) Expand all
276 299
277 // When the server thread serving clients is in the INITIAL state, 300 // When the server thread serving clients is in the INITIAL state,
278 // try to connect to the pipe asynchronously. If the connection 301 // try to connect to the pipe asynchronously. If the connection
279 // finishes synchronously, directly go into the CONNECTED state; 302 // finishes synchronously, directly go into the CONNECTED state;
280 // otherwise go into the CONNECTING state. For any problems, go 303 // otherwise go into the CONNECTING state. For any problems, go
281 // into the ERROR state. 304 // into the ERROR state.
282 void CrashGenerationServer::HandleInitialState() { 305 void CrashGenerationServer::HandleInitialState() {
283 assert(server_state_ == IPC_SERVER_STATE_INITIAL); 306 assert(server_state_ == IPC_SERVER_STATE_INITIAL);
284 307
285 if (!ResetEvent(overlapped_.hEvent)) { 308 if (!ResetEvent(overlapped_.hEvent)) {
286 server_state_ = IPC_SERVER_STATE_ERROR; 309 EnterErrorState();
287 return; 310 } else {
311 bool success = ConnectNamedPipe(pipe_, &overlapped_) != FALSE;
312
313 // From MSDN, it is not clear that when ConnectNamedPipe is used
314 // in an overlapped mode, will it ever return non-zero value, and
315 // if so, in what cases.
316 assert(!success);
317
318 DWORD error_code = GetLastError();
319 switch (error_code) {
320 case ERROR_IO_PENDING:
321 EnterStateWhenSignaled(IPC_SERVER_STATE_CONNECTING);
322 break;
323
324 case ERROR_PIPE_CONNECTED:
325 EnterStateImmediately(IPC_SERVER_STATE_CONNECTED);
326 break;
327
328 default:
329 EnterErrorState();
330 break;
331 }
288 } 332 }
289 333
290 bool success = ConnectNamedPipe(pipe_, &overlapped_) != FALSE; 334 if (!SetEvent(server_start_complete_event_)) {
291 335 EnterErrorState();
292 // From MSDN, it is not clear that when ConnectNamedPipe is used
293 // in an overlapped mode, will it ever return non-zero value, and
294 // if so, in what cases.
295 assert(!success);
296
297 DWORD error_code = GetLastError();
298 switch (error_code) {
299 case ERROR_IO_PENDING:
300 server_state_ = IPC_SERVER_STATE_CONNECTING;
301 break;
302
303 case ERROR_PIPE_CONNECTED:
304 if (SetEvent(overlapped_.hEvent)) {
305 server_state_ = IPC_SERVER_STATE_CONNECTED;
306 } else {
307 server_state_ = IPC_SERVER_STATE_ERROR;
308 }
309 break;
310
311 default:
312 server_state_ = IPC_SERVER_STATE_ERROR;
313 break;
314 } 336 }
315 } 337 }
316 338
317 // When the server thread serving the clients is in the CONNECTING state, 339 // When the server thread serving the clients is in the CONNECTING state,
318 // try to get the result of the asynchronous connection request using 340 // try to get the result of the asynchronous connection request using
319 // the OVERLAPPED object. If the result indicates the connection is done, 341 // the OVERLAPPED object. If the result indicates the connection is done,
320 // go into the CONNECTED state. If the result indicates I/O is still 342 // go into the CONNECTED state. If the result indicates I/O is still
321 // INCOMPLETE, remain in the CONNECTING state. For any problems, 343 // INCOMPLETE, remain in the CONNECTING state. For any problems,
322 // go into the DISCONNECTING state. 344 // go into the DISCONNECTING state.
323 void CrashGenerationServer::HandleConnectingState() { 345 void CrashGenerationServer::HandleConnectingState() {
324 assert(server_state_ == IPC_SERVER_STATE_CONNECTING); 346 assert(server_state_ == IPC_SERVER_STATE_CONNECTING);
325 347
326 DWORD bytes_count = 0; 348 DWORD bytes_count = 0;
327 bool success = GetOverlappedResult(pipe_, 349 bool success = GetOverlappedResult(pipe_,
328 &overlapped_, 350 &overlapped_,
329 &bytes_count, 351 &bytes_count,
330 FALSE) != FALSE; 352 FALSE) != FALSE;
331 353
332 if (success) { 354 if (success) {
333 server_state_ = IPC_SERVER_STATE_CONNECTED; 355 EnterStateImmediately(IPC_SERVER_STATE_CONNECTED);
334 return; 356 } else if (GetLastError() != ERROR_IO_INCOMPLETE) {
335 } 357 EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
336
337 if (GetLastError() != ERROR_IO_INCOMPLETE) {
338 server_state_ = IPC_SERVER_STATE_DISCONNECTING;
339 } 358 }
340 } 359 }
341 360
342 // When the server thread serving the clients is in the CONNECTED state, 361 // When the server thread serving the clients is in the CONNECTED state,
343 // try to issue an asynchronous read from the pipe. If read completes 362 // try to issue an asynchronous read from the pipe. If read completes
344 // synchronously or if I/O is pending then go into the READING state. 363 // synchronously or if I/O is pending then go into the READING state.
345 // For any problems, go into the DISCONNECTING state. 364 // For any problems, go into the DISCONNECTING state.
346 void CrashGenerationServer::HandleConnectedState() { 365 void CrashGenerationServer::HandleConnectedState() {
347 assert(server_state_ == IPC_SERVER_STATE_CONNECTED); 366 assert(server_state_ == IPC_SERVER_STATE_CONNECTED);
348 367
349 DWORD bytes_count = 0; 368 DWORD bytes_count = 0;
350 memset(&msg_, 0, sizeof(msg_)); 369 memset(&msg_, 0, sizeof(msg_));
351 bool success = ReadFile(pipe_, 370 bool success = ReadFile(pipe_,
352 &msg_, 371 &msg_,
353 sizeof(msg_), 372 sizeof(msg_),
354 &bytes_count, 373 &bytes_count,
355 &overlapped_) != FALSE; 374 &overlapped_) != FALSE;
356 375
357 // Note that the asynchronous read issued above can finish before the 376 // Note that the asynchronous read issued above can finish before the
358 // code below executes. But, it is okay to change state after issuing 377 // code below executes. But, it is okay to change state after issuing
359 // the asynchronous read. This is because even if the asynchronous read 378 // the asynchronous read. This is because even if the asynchronous read
360 // is done, the callback for it would not be executed until the current 379 // is done, the callback for it would not be executed until the current
361 // thread finishes its execution. 380 // thread finishes its execution.
362 if (success || GetLastError() == ERROR_IO_PENDING) { 381 if (success || GetLastError() == ERROR_IO_PENDING) {
363 server_state_ = IPC_SERVER_STATE_READING; 382 EnterStateWhenSignaled(IPC_SERVER_STATE_READING);
364 } else { 383 } else {
365 server_state_ = IPC_SERVER_STATE_DISCONNECTING; 384 EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
366 } 385 }
367 } 386 }
368 387
369 // When the server thread serving the clients is in the READING state, 388 // When the server thread serving the clients is in the READING state,
370 // try to get the result of the async read. If async read is done, 389 // try to get the result of the async read. If async read is done,
371 // go into the READ_DONE state. For any problems, go into the 390 // go into the READ_DONE state. For any problems, go into the
372 // DISCONNECTING state. 391 // DISCONNECTING state.
373 void CrashGenerationServer::HandleReadingState() { 392 void CrashGenerationServer::HandleReadingState() {
374 assert(server_state_ == IPC_SERVER_STATE_READING); 393 assert(server_state_ == IPC_SERVER_STATE_READING);
375 394
376 DWORD bytes_count = 0; 395 DWORD bytes_count = 0;
377 bool success = GetOverlappedResult(pipe_, 396 bool success = GetOverlappedResult(pipe_,
378 &overlapped_, 397 &overlapped_,
379 &bytes_count, 398 &bytes_count,
380 FALSE) != FALSE; 399 FALSE) != FALSE;
381 400
382 if (success && bytes_count == sizeof(ProtocolMessage)) { 401 if (success && bytes_count == sizeof(ProtocolMessage)) {
383 server_state_ = IPC_SERVER_STATE_READ_DONE; 402 EnterStateImmediately(IPC_SERVER_STATE_READ_DONE);
384 return; 403 } else {
404 // We should never get an I/O incomplete since we should not execute this
405 // unless the Read has finished and the overlapped event is signaled. If
406 // we do get INCOMPLETE, we have a bug in our code.
407 assert(GetLastError() != ERROR_IO_INCOMPLETE);
408
409 EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
385 } 410 }
386
387 DWORD error_code;
388 error_code = GetLastError();
389
390 // We should never get an I/O incomplete since we should not execute this
391 // unless the Read has finished and the overlapped event is signaled. If
392 // we do get INCOMPLETE, we have a bug in our code.
393 assert(error_code != ERROR_IO_INCOMPLETE);
394
395 server_state_ = IPC_SERVER_STATE_DISCONNECTING;
396 } 411 }
397 412
398 // When the server thread serving the client is in the READ_DONE state, 413 // When the server thread serving the client is in the READ_DONE state,
399 // validate the client's request message, register the client by 414 // validate the client's request message, register the client by
400 // creating appropriate objects and prepare the response. Then try to 415 // creating appropriate objects and prepare the response. Then try to
401 // write the response to the pipe asynchronously. If that succeeds, 416 // write the response to the pipe asynchronously. If that succeeds,
402 // go into the WRITING state. For any problems, go into the DISCONNECTING 417 // go into the WRITING state. For any problems, go into the DISCONNECTING
403 // state. 418 // state.
404 void CrashGenerationServer::HandleReadDoneState() { 419 void CrashGenerationServer::HandleReadDoneState() {
405 assert(server_state_ == IPC_SERVER_STATE_READ_DONE); 420 assert(server_state_ == IPC_SERVER_STATE_READ_DONE);
406 421
407 if (!IsClientRequestValid(msg_)) { 422 if (!IsClientRequestValid(msg_)) {
408 server_state_ = IPC_SERVER_STATE_DISCONNECTING; 423 EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
409 return; 424 return;
410 } 425 }
411 426
412 scoped_ptr<ClientInfo> client_info( 427 scoped_ptr<ClientInfo> client_info(
413 new ClientInfo(this, 428 new ClientInfo(this,
414 msg_.pid, 429 msg_.pid,
415 msg_.dump_type, 430 msg_.dump_type,
416 msg_.thread_id, 431 msg_.thread_id,
417 msg_.exception_pointers, 432 msg_.exception_pointers,
418 msg_.assert_info, 433 msg_.assert_info,
419 msg_.custom_client_info)); 434 msg_.custom_client_info));
420 435
421 if (!client_info->Initialize()) { 436 if (!client_info->Initialize()) {
422 server_state_ = IPC_SERVER_STATE_DISCONNECTING; 437 EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
423 return; 438 return;
424 } 439 }
425 440
441 // Issues an asynchronous WriteFile call if successful.
442 // Iff successful, assigns ownership of the client_info pointer to the server
443 // instance, in which case we must be sure not to free it in this function.
426 if (!RespondToClient(client_info.get())) { 444 if (!RespondToClient(client_info.get())) {
427 server_state_ = IPC_SERVER_STATE_DISCONNECTING; 445 EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
428 return; 446 return;
429 } 447 }
430 448
449 client_info_ = client_info.release();
450
431 // Note that the asynchronous write issued by RespondToClient function 451 // Note that the asynchronous write issued by RespondToClient function
432 // can finish before the code below executes. But it is okay to change 452 // can finish before the code below executes. But it is okay to change
433 // state after issuing the asynchronous write. This is because even if 453 // state after issuing the asynchronous write. This is because even if
434 // the asynchronous write is done, the callback for it would not be 454 // the asynchronous write is done, the callback for it would not be
435 // executed until the current thread finishes its execution. 455 // executed until the current thread finishes its execution.
436 server_state_ = IPC_SERVER_STATE_WRITING; 456 EnterStateWhenSignaled(IPC_SERVER_STATE_WRITING);
437 client_info_ = client_info.release();
438 } 457 }
439 458
440 // When the server thread serving the clients is in the WRITING state, 459 // When the server thread serving the clients is in the WRITING state,
441 // try to get the result of the async write. If the async write is done, 460 // try to get the result of the async write. If the async write is done,
442 // go into the WRITE_DONE state. For any problems, go into the 461 // go into the WRITE_DONE state. For any problems, go into the
443 // DISONNECTING state. 462 // DISONNECTING state.
444 void CrashGenerationServer::HandleWritingState() { 463 void CrashGenerationServer::HandleWritingState() {
445 assert(server_state_ == IPC_SERVER_STATE_WRITING); 464 assert(server_state_ == IPC_SERVER_STATE_WRITING);
446 465
447 DWORD bytes_count = 0; 466 DWORD bytes_count = 0;
448 bool success = GetOverlappedResult(pipe_, 467 bool success = GetOverlappedResult(pipe_,
449 &overlapped_, 468 &overlapped_,
450 &bytes_count, 469 &bytes_count,
451 FALSE) != FALSE; 470 FALSE) != FALSE;
452 471
453 if (success) { 472 if (success) {
454 server_state_ = IPC_SERVER_STATE_WRITE_DONE; 473 EnterStateImmediately(IPC_SERVER_STATE_WRITE_DONE);
455 return; 474 return;
456 } 475 }
457 476
458 DWORD error_code;
459 error_code = GetLastError();
460
461 // We should never get an I/O incomplete since we should not execute this 477 // We should never get an I/O incomplete since we should not execute this
462 // unless the Write has finished and the overlapped event is signaled. If 478 // unless the Write has finished and the overlapped event is signaled. If
463 // we do get INCOMPLETE, we have a bug in our code. 479 // we do get INCOMPLETE, we have a bug in our code.
464 assert(error_code != ERROR_IO_INCOMPLETE); 480 assert(GetLastError() != ERROR_IO_INCOMPLETE);
465 481
466 server_state_ = IPC_SERVER_STATE_DISCONNECTING; 482 EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
467 } 483 }
468 484
469 // When the server thread serving the clients is in the WRITE_DONE state, 485 // When the server thread serving the clients is in the WRITE_DONE state,
470 // try to issue an async read on the pipe. If the read completes synchronously 486 // try to issue an async read on the pipe. If the read completes synchronously
471 // or if I/O is still pending then go into the READING_ACK state. For any 487 // or if I/O is still pending then go into the READING_ACK state. For any
472 // issues, go into the DISCONNECTING state. 488 // issues, go into the DISCONNECTING state.
473 void CrashGenerationServer::HandleWriteDoneState() { 489 void CrashGenerationServer::HandleWriteDoneState() {
474 assert(server_state_ == IPC_SERVER_STATE_WRITE_DONE); 490 assert(server_state_ == IPC_SERVER_STATE_WRITE_DONE);
475 491
476 server_state_ = IPC_SERVER_STATE_READING_ACK;
477
478 DWORD bytes_count = 0; 492 DWORD bytes_count = 0;
479 bool success = ReadFile(pipe_, 493 bool success = ReadFile(pipe_,
480 &msg_, 494 &msg_,
481 sizeof(msg_), 495 sizeof(msg_),
482 &bytes_count, 496 &bytes_count,
483 &overlapped_) != FALSE; 497 &overlapped_) != FALSE;
484 498
485 if (success) { 499 if (success) {
486 return; 500 EnterStateImmediately(IPC_SERVER_STATE_READING_ACK);
487 } 501 } else if (GetLastError() == ERROR_IO_PENDING) {
488 502 EnterStateWhenSignaled(IPC_SERVER_STATE_READING_ACK);
489 DWORD error_code = GetLastError(); 503 } else {
490 504 EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
491 if (error_code != ERROR_IO_PENDING) {
492 server_state_ = IPC_SERVER_STATE_DISCONNECTING;
493 } 505 }
494 } 506 }
495 507
496 // When the server thread serving the clients is in the READING_ACK state, 508 // When the server thread serving the clients is in the READING_ACK state,
497 // try to get result of async read. Go into the DISCONNECTING state. 509 // try to get result of async read. Go into the DISCONNECTING state.
498 void CrashGenerationServer::HandleReadingAckState() { 510 void CrashGenerationServer::HandleReadingAckState() {
499 assert(server_state_ == IPC_SERVER_STATE_READING_ACK); 511 assert(server_state_ == IPC_SERVER_STATE_READING_ACK);
500 512
501 DWORD bytes_count = 0; 513 DWORD bytes_count = 0;
502 bool success = GetOverlappedResult(pipe_, 514 bool success = GetOverlappedResult(pipe_,
503 &overlapped_, 515 &overlapped_,
504 &bytes_count, 516 &bytes_count,
505 FALSE) != FALSE; 517 FALSE) != FALSE;
506 518
507 if (success) { 519 if (success) {
508 // The connection handshake with the client is now complete; perform 520 // The connection handshake with the client is now complete; perform
509 // the callback. 521 // the callback.
510 if (connect_callback_) { 522 if (connect_callback_) {
511 connect_callback_(connect_context_, client_info_); 523 connect_callback_(connect_context_, client_info_);
512 } 524 }
513 } else { 525 } else {
514 DWORD error_code = GetLastError();
515
516 // We should never get an I/O incomplete since we should not execute this 526 // We should never get an I/O incomplete since we should not execute this
517 // unless the Read has finished and the overlapped event is signaled. If 527 // unless the Read has finished and the overlapped event is signaled. If
518 // we do get INCOMPLETE, we have a bug in our code. 528 // we do get INCOMPLETE, we have a bug in our code.
519 assert(error_code != ERROR_IO_INCOMPLETE); 529 assert(GetLastError() != ERROR_IO_INCOMPLETE);
520 } 530 }
521 531
522 server_state_ = IPC_SERVER_STATE_DISCONNECTING; 532 EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
523 } 533 }
524 534
525 // When the server thread serving the client is in the DISCONNECTING state, 535 // When the server thread serving the client is in the DISCONNECTING state,
526 // disconnect from the pipe and reset the event. If anything fails, go into 536 // disconnect from the pipe and reset the event. If anything fails, go into
527 // the ERROR state. If it goes well, go into the INITIAL state and set the 537 // the ERROR state. If it goes well, go into the INITIAL state and set the
528 // event to start all over again. 538 // event to start all over again.
529 void CrashGenerationServer::HandleDisconnectingState() { 539 void CrashGenerationServer::HandleDisconnectingState() {
530 assert(server_state_ == IPC_SERVER_STATE_DISCONNECTING); 540 assert(server_state_ == IPC_SERVER_STATE_DISCONNECTING);
531 541
532 // Done serving the client. 542 // Done serving the client.
533 client_info_ = NULL; 543 client_info_ = NULL;
534 544
535 overlapped_.Internal = NULL; 545 overlapped_.Internal = NULL;
536 overlapped_.InternalHigh = NULL; 546 overlapped_.InternalHigh = NULL;
537 overlapped_.Offset = 0; 547 overlapped_.Offset = 0;
538 overlapped_.OffsetHigh = 0; 548 overlapped_.OffsetHigh = 0;
539 overlapped_.Pointer = NULL; 549 overlapped_.Pointer = NULL;
540 550
541 if (!ResetEvent(overlapped_.hEvent)) { 551 if (!ResetEvent(overlapped_.hEvent)) {
542 server_state_ = IPC_SERVER_STATE_ERROR; 552 EnterErrorState();
543 return; 553 return;
544 } 554 }
545 555
546 if (!DisconnectNamedPipe(pipe_)) { 556 if (!DisconnectNamedPipe(pipe_)) {
547 server_state_ = IPC_SERVER_STATE_ERROR; 557 EnterErrorState();
548 return; 558 return;
549 } 559 }
550 560
551 // If the server is shutting down do not connect to the 561 // If the server is shutting down do not connect to the
552 // next client. 562 // next client.
553 if (shutting_down_) { 563 if (shutting_down_) {
554 return; 564 return;
555 } 565 }
556 566
557 server_state_ = IPC_SERVER_STATE_INITIAL; 567 EnterStateImmediately(IPC_SERVER_STATE_INITIAL);
568 }
569
570 void CrashGenerationServer::EnterErrorState() {
Erik Wright 2010/09/16 21:06:59 May these functions aid in readability, and preven
571 SetEvent(overlapped_.hEvent);
572 server_state_ = IPC_SERVER_STATE_ERROR;
573 }
574
575 void CrashGenerationServer::EnterStateWhenSignaled(IPCServerState state) {
576 server_state_ = state;
577 }
578
579 void CrashGenerationServer::EnterStateImmediately(IPCServerState state) {
580 server_state_ = state;
581
558 if (!SetEvent(overlapped_.hEvent)) { 582 if (!SetEvent(overlapped_.hEvent)) {
559 server_state_ = IPC_SERVER_STATE_ERROR; 583 server_state_ = IPC_SERVER_STATE_ERROR;
560 } 584 }
561 } 585 }
562 586
563 bool CrashGenerationServer::PrepareReply(const ClientInfo& client_info, 587 bool CrashGenerationServer::PrepareReply(const ClientInfo& client_info,
564 ProtocolMessage* reply) const { 588 ProtocolMessage* reply) const {
565 reply->tag = MESSAGE_TAG_REGISTRATION_RESPONSE; 589 reply->tag = MESSAGE_TAG_REGISTRATION_RESPONSE;
566 reply->pid = GetCurrentProcessId(); 590 reply->pid = GetCurrentProcessId();
567 591
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
613 &reply->server_alive_handle, 637 &reply->server_alive_handle,
614 kMutexAccess, 638 kMutexAccess,
615 FALSE, 639 FALSE,
616 0)) { 640 0)) {
617 return false; 641 return false;
618 } 642 }
619 643
620 return true; 644 return true;
621 } 645 }
622 646
623 bool CrashGenerationServer::RespondToClient(ClientInfo* client_info) { 647 bool CrashGenerationServer::RespondToClient(ClientInfo* client_info) {
Erik Wright 2010/09/16 21:06:59 There was a bug in this function where it could ta
624 ProtocolMessage reply; 648 ProtocolMessage reply;
625 if (!PrepareReply(*client_info, &reply)) { 649 if (!PrepareReply(*client_info, &reply)) {
626 return false; 650 return false;
627 } 651 }
628 652
629 if (!AddClient(client_info)) {
630 return false;
631 }
632
633 DWORD bytes_count = 0; 653 DWORD bytes_count = 0;
634 bool success = WriteFile(pipe_, 654 bool success = WriteFile(pipe_,
635 &reply, 655 &reply,
636 sizeof(reply), 656 sizeof(reply),
637 &bytes_count, 657 &bytes_count,
638 &overlapped_) != FALSE; 658 &overlapped_) != FALSE;
639 659
640 return success || GetLastError() == ERROR_IO_PENDING; 660 if (!success && GetLastError() != ERROR_IO_PENDING) {
661 return false;
662 }
663
664 // Takes over ownership of client_info. We MUST return true if AddClient
665 // succeeds.
666 if (!AddClient(client_info)) {
667 return false;
668 }
669
670 return true;
641 } 671 }
642 672
643 // The server thread servicing the clients runs this method. The method 673 // The server thread servicing the clients runs this method. The method
644 // implements the state machine described in ReadMe.txt along with the 674 // implements the state machine described in ReadMe.txt along with the
645 // helper methods HandleXXXState. 675 // helper methods HandleXXXState.
646 void CrashGenerationServer::HandleConnectionRequest() { 676 void CrashGenerationServer::HandleConnectionRequest() {
647 // If we are shutting doen then get into ERROR state, reset the event so more 677 // If we are shutting doen then get into ERROR state, reset the event so more
648 // workers don't run and return immediately. 678 // workers don't run and return immediately.
649 if (shutting_down_) { 679 if (shutting_down_) {
650 server_state_ = IPC_SERVER_STATE_ERROR; 680 server_state_ = IPC_SERVER_STATE_ERROR;
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
732 { 762 {
733 AutoCriticalSection lock(&clients_sync_); 763 AutoCriticalSection lock(&clients_sync_);
734 clients_.push_back(client_info); 764 clients_.push_back(client_info);
735 } 765 }
736 766
737 return true; 767 return true;
738 } 768 }
739 769
740 // static 770 // static
741 void CALLBACK CrashGenerationServer::OnPipeConnected(void* context, BOOLEAN) { 771 void CALLBACK CrashGenerationServer::OnPipeConnected(void* context, BOOLEAN) {
742 assert (context); 772 assert(context);
743 773
744 CrashGenerationServer* obj = 774 CrashGenerationServer* obj =
745 reinterpret_cast<CrashGenerationServer*>(context); 775 reinterpret_cast<CrashGenerationServer*>(context);
746 obj->HandleConnectionRequest(); 776 obj->HandleConnectionRequest();
747 } 777 }
748 778
749 // static 779 // static
750 void CALLBACK CrashGenerationServer::OnDumpRequest(void* context, BOOLEAN) { 780 void CALLBACK CrashGenerationServer::OnDumpRequest(void* context, BOOLEAN) {
751 assert(context); 781 assert(context);
752 ClientInfo* client_info = reinterpret_cast<ClientInfo*>(context); 782 ClientInfo* client_info = reinterpret_cast<ClientInfo*>(context);
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
845 client_thread_id, 875 client_thread_id,
846 GetCurrentThreadId(), 876 GetCurrentThreadId(),
847 client_ex_info, 877 client_ex_info,
848 client.assert_info(), 878 client.assert_info(),
849 client.dump_type(), 879 client.dump_type(),
850 true, 880 true,
851 dump_path); 881 dump_path);
852 } 882 }
853 883
854 } // namespace google_breakpad 884 } // namespace google_breakpad
OLDNEW
« no previous file with comments | « src/client/windows/breakpad_client.gyp ('k') | src/client/windows/crash_generation/crash_generation_server.h » ('j') | no next file with comments »

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld 1004:630ec63f810e-tainted