PageRenderTime 56ms CodeModel.GetById 8ms app.highlight 42ms RepoModel.GetById 1ms app.codeStats 0ms

/thirdparty/breakpad/client/windows/crash_generation/crash_generation_server.cc

http://github.com/tomahawk-player/tomahawk
C++ | 900 lines | 580 code | 152 blank | 168 comment | 112 complexity | a94fd8e9902472068b4245ee61b7b591 MD5 | raw file
  1// Copyright (c) 2008, Google Inc.
  2// All rights reserved.
  3//
  4// Redistribution and use in source and binary forms, with or without
  5// modification, are permitted provided that the following conditions are
  6// met:
  7//
  8//     * Redistributions of source code must retain the above copyright
  9// notice, this list of conditions and the following disclaimer.
 10//     * Redistributions in binary form must reproduce the above
 11// copyright notice, this list of conditions and the following disclaimer
 12// in the documentation and/or other materials provided with the
 13// distribution.
 14//     * Neither the name of Google Inc. nor the names of its
 15// contributors may be used to endorse or promote products derived from
 16// this software without specific prior written permission.
 17//
 18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 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.
 29
 30#include "client/windows/crash_generation/crash_generation_server.h"
 31#include <windows.h>
 32#include <cassert>
 33#include <list>
 34#include "client/windows/common/auto_critical_section.h"
 35#include "processor/scoped_ptr.h"
 36
 37#include "client/windows/crash_generation/client_info.h"
 38
 39namespace google_breakpad {
 40
 41// Output buffer size.
 42static const size_t kOutBufferSize = 64;
 43
 44// Input buffer size.
 45static const size_t kInBufferSize = 64;
 46
 47// Access flags for the client on the dump request event.
 48static const DWORD kDumpRequestEventAccess = EVENT_MODIFY_STATE;
 49
 50// Access flags for the client on the dump generated event.
 51static const DWORD kDumpGeneratedEventAccess = EVENT_MODIFY_STATE |
 52                                               SYNCHRONIZE;
 53
 54// Access flags for the client on the mutex.
 55static const DWORD kMutexAccess = SYNCHRONIZE;
 56
 57// Attribute flags for the pipe.
 58static const DWORD kPipeAttr = FILE_FLAG_FIRST_PIPE_INSTANCE |
 59                               PIPE_ACCESS_DUPLEX |
 60                               FILE_FLAG_OVERLAPPED;
 61
 62// Mode for the pipe.
 63static const DWORD kPipeMode = PIPE_TYPE_MESSAGE |
 64                               PIPE_READMODE_MESSAGE |
 65                               PIPE_WAIT;
 66
 67// For pipe I/O, execute the callback in the wait thread itself,
 68// since the callback does very little work. The callback executes
 69// the code for one of the states of the server state machine and
 70// the code for all of the states perform async I/O and hence
 71// finish very quickly.
 72static const ULONG kPipeIOThreadFlags = WT_EXECUTEINWAITTHREAD;
 73
 74// Dump request threads will, most likely, generate dumps. That may
 75// take some time to finish, so specify WT_EXECUTELONGFUNCTION flag.
 76static const ULONG kDumpRequestThreadFlags = WT_EXECUTEINWAITTHREAD |
 77                                             WT_EXECUTELONGFUNCTION;
 78
 79// Maximum delay during server shutdown if some work items
 80// are still executing.
 81static const int kShutdownDelayMs = 10000;
 82
 83// Interval for each sleep during server shutdown.
 84static const int kShutdownSleepIntervalMs = 5;
 85
 86static bool IsClientRequestValid(const ProtocolMessage& msg) {
 87  return msg.tag == MESSAGE_TAG_UPLOAD_REQUEST ||
 88         (msg.tag == MESSAGE_TAG_REGISTRATION_REQUEST &&
 89          msg.id != 0 &&
 90          msg.thread_id != NULL &&
 91          msg.exception_pointers != NULL &&
 92          msg.assert_info != NULL);
 93}
 94
 95CrashGenerationServer::CrashGenerationServer(
 96    const std::wstring& pipe_name,
 97    SECURITY_ATTRIBUTES* pipe_sec_attrs,
 98    OnClientConnectedCallback connect_callback,
 99    void* connect_context,
100    OnClientDumpRequestCallback dump_callback,
101    void* dump_context,
102    OnClientExitedCallback exit_callback,
103    void* exit_context,
104    OnClientUploadRequestCallback upload_request_callback,
105    void* upload_context,
106    bool generate_dumps,
107    const std::wstring* dump_path)
108    : pipe_name_(pipe_name),
109      pipe_sec_attrs_(pipe_sec_attrs),
110      pipe_(NULL),
111      pipe_wait_handle_(NULL),
112      server_alive_handle_(NULL),
113      connect_callback_(connect_callback),
114      connect_context_(connect_context),
115      dump_callback_(dump_callback),
116      dump_context_(dump_context),
117      exit_callback_(exit_callback),
118      exit_context_(exit_context),
119      upload_request_callback_(upload_request_callback),
120      upload_context_(upload_context),
121      generate_dumps_(generate_dumps),
122      dump_generator_(NULL),
123      server_state_(IPC_SERVER_STATE_UNINITIALIZED),
124      shutting_down_(false),
125      overlapped_(),
126      client_info_(NULL),
127      cleanup_item_count_(0) {
128  InitializeCriticalSection(&sync_);
129
130  if (dump_path) {
131    dump_generator_.reset(new MinidumpGenerator(*dump_path));
132  }
133}
134
135CrashGenerationServer::~CrashGenerationServer() {
136  // New scope to release the lock automatically.
137  {
138    AutoCriticalSection lock(&sync_);
139
140    // Indicate to existing threads that server is shutting down.
141    shutting_down_ = true;
142
143    // Even if there are no current worker threads running, it is possible that
144    // an I/O request is pending on the pipe right now but not yet done.
145    // In fact, it's very likely this is the case unless we are in an ERROR
146    // state. If we don't wait for the pending I/O to be done, then when the I/O
147    // completes, it may write to invalid memory. AppVerifier will flag this
148    // problem too. So we disconnect from the pipe and then wait for the server
149    // to get into error state so that the pending I/O will fail and get
150    // cleared.
151    DisconnectNamedPipe(pipe_);
152    int num_tries = 100;
153    while (num_tries-- && server_state_ != IPC_SERVER_STATE_ERROR) {
154      lock.Release();
155      Sleep(10);
156      lock.Acquire();
157    }
158
159    // Unregister wait on the pipe.
160    if (pipe_wait_handle_) {
161      // Wait for already executing callbacks to finish.
162      UnregisterWaitEx(pipe_wait_handle_, INVALID_HANDLE_VALUE);
163    }
164
165    // Close the pipe to avoid further client connections.
166    if (pipe_) {
167      CloseHandle(pipe_);
168    }
169
170    // Request all ClientInfo objects to unregister all waits.
171    std::list<ClientInfo*>::iterator iter;
172    for (iter = clients_.begin(); iter != clients_.end(); ++iter) {
173      ClientInfo* client_info = *iter;
174      client_info->UnregisterWaits();
175    }
176  }
177
178  // Now that all waits have been unregistered, wait for some time
179  // for all pending work items to finish.
180  int total_wait = 0;
181  while (cleanup_item_count_ > 0) {
182    Sleep(kShutdownSleepIntervalMs);
183
184    total_wait += kShutdownSleepIntervalMs;
185
186    if (total_wait >= kShutdownDelayMs) {
187      break;
188    }
189  }
190
191  // New scope to hold the lock for the shortest time.
192  {
193    AutoCriticalSection lock(&sync_);
194
195    // Clean up all the ClientInfo objects.
196    std::list<ClientInfo*>::iterator iter;
197    for (iter = clients_.begin(); iter != clients_.end(); ++iter) {
198      ClientInfo* client_info = *iter;
199      delete client_info;
200    }
201
202    if (server_alive_handle_) {
203      // Release the mutex before closing the handle so that clients requesting
204      // dumps wait for a long time for the server to generate a dump.
205      ReleaseMutex(server_alive_handle_);
206      CloseHandle(server_alive_handle_);
207    }
208
209    if (overlapped_.hEvent) {
210      CloseHandle(overlapped_.hEvent);
211    }
212  }
213
214  DeleteCriticalSection(&sync_);
215}
216
217bool CrashGenerationServer::Start() {
218  AutoCriticalSection lock(&sync_);
219
220  if (server_state_ != IPC_SERVER_STATE_UNINITIALIZED) {
221    return false;
222  }
223
224  server_state_ = IPC_SERVER_STATE_INITIAL;
225
226  server_alive_handle_ = CreateMutex(NULL, TRUE, NULL);
227  if (!server_alive_handle_) {
228    return false;
229  }
230
231  // Event to signal the client connection and pipe reads and writes.
232  overlapped_.hEvent = CreateEvent(NULL,   // Security descriptor.
233                                   TRUE,   // Manual reset.
234                                   FALSE,  // Initially signaled.
235                                   NULL);  // Name.
236  if (!overlapped_.hEvent) {
237    return false;
238  }
239
240  // Register a callback with the thread pool for the client connection.
241  if (!RegisterWaitForSingleObject(&pipe_wait_handle_,
242                                   overlapped_.hEvent,
243                                   OnPipeConnected,
244                                   this,
245                                   INFINITE,
246                                   kPipeIOThreadFlags)) {
247    return false;
248  }
249
250  pipe_ = CreateNamedPipe(pipe_name_.c_str(),
251                          kPipeAttr,
252                          kPipeMode,
253                          1,
254                          kOutBufferSize,
255                          kInBufferSize,
256                          0,
257                          pipe_sec_attrs_);
258  if (pipe_ == INVALID_HANDLE_VALUE) {
259    return false;
260  }
261
262  // Kick-start the state machine. This will initiate an asynchronous wait
263  // for client connections.
264  HandleInitialState();
265
266  // If we are in error state, it's because we failed to start listening.
267  return server_state_ != IPC_SERVER_STATE_ERROR;
268}
269
270// If the server thread serving clients ever gets into the
271// ERROR state, reset the event, close the pipe and remain
272// in the error state forever. Error state means something
273// that we didn't account for has happened, and it's dangerous
274// to do anything unknowingly.
275void CrashGenerationServer::HandleErrorState() {
276  assert(server_state_ == IPC_SERVER_STATE_ERROR);
277
278  // If the server is shutting down anyway, don't clean up
279  // here since shut down process will clean up.
280  if (shutting_down_) {
281    return;
282  }
283
284  if (pipe_wait_handle_) {
285    UnregisterWait(pipe_wait_handle_);
286    pipe_wait_handle_ = NULL;
287  }
288
289  if (pipe_) {
290    CloseHandle(pipe_);
291    pipe_ = NULL;
292  }
293
294  if (overlapped_.hEvent) {
295    CloseHandle(overlapped_.hEvent);
296    overlapped_.hEvent = NULL;
297  }
298}
299
300// When the server thread serving clients is in the INITIAL state,
301// try to connect to the pipe asynchronously. If the connection
302// finishes synchronously, directly go into the CONNECTED state;
303// otherwise go into the CONNECTING state. For any problems, go
304// into the ERROR state.
305void CrashGenerationServer::HandleInitialState() {
306  assert(server_state_ == IPC_SERVER_STATE_INITIAL);
307
308  if (!ResetEvent(overlapped_.hEvent)) {
309    EnterErrorState();
310    return;
311  }
312
313  bool success = ConnectNamedPipe(pipe_, &overlapped_) != FALSE;
314  DWORD error_code = success ? ERROR_SUCCESS : GetLastError();
315
316  // From MSDN, it is not clear that when ConnectNamedPipe is used
317  // in an overlapped mode, will it ever return non-zero value, and
318  // if so, in what cases.
319  assert(!success);
320
321  switch (error_code) {
322    case ERROR_IO_PENDING:
323      EnterStateWhenSignaled(IPC_SERVER_STATE_CONNECTING);
324      break;
325
326    case ERROR_PIPE_CONNECTED:
327      EnterStateImmediately(IPC_SERVER_STATE_CONNECTED);
328      break;
329
330    default:
331      EnterErrorState();
332      break;
333  }
334}
335
336// When the server thread serving the clients is in the CONNECTING state,
337// try to get the result of the asynchronous connection request using
338// the OVERLAPPED object. If the result indicates the connection is done,
339// go into the CONNECTED state. If the result indicates I/O is still
340// INCOMPLETE, remain in the CONNECTING state. For any problems,
341// go into the DISCONNECTING state.
342void CrashGenerationServer::HandleConnectingState() {
343  assert(server_state_ == IPC_SERVER_STATE_CONNECTING);
344
345  DWORD bytes_count = 0;
346  bool success = GetOverlappedResult(pipe_,
347                                     &overlapped_,
348                                     &bytes_count,
349                                     FALSE) != FALSE;
350  DWORD error_code = success ? ERROR_SUCCESS : GetLastError();
351
352  if (success) {
353    EnterStateImmediately(IPC_SERVER_STATE_CONNECTED);
354  } else if (error_code != ERROR_IO_INCOMPLETE) {
355    EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
356  } else {
357    // remain in CONNECTING state
358  }
359}
360
361// When the server thread serving the clients is in the CONNECTED state,
362// try to issue an asynchronous read from the pipe. If read completes
363// synchronously or if I/O is pending then go into the READING state.
364// For any problems, go into the DISCONNECTING state.
365void CrashGenerationServer::HandleConnectedState() {
366  assert(server_state_ == IPC_SERVER_STATE_CONNECTED);
367
368  DWORD bytes_count = 0;
369  memset(&msg_, 0, sizeof(msg_));
370  bool success = ReadFile(pipe_,
371                          &msg_,
372                          sizeof(msg_),
373                          &bytes_count,
374                          &overlapped_) != FALSE;
375  DWORD error_code = success ? ERROR_SUCCESS : GetLastError();
376
377  // Note that the asynchronous read issued above can finish before the
378  // code below executes. But, it is okay to change state after issuing
379  // the asynchronous read. This is because even if the asynchronous read
380  // is done, the callback for it would not be executed until the current
381  // thread finishes its execution.
382  if (success || error_code == ERROR_IO_PENDING) {
383    EnterStateWhenSignaled(IPC_SERVER_STATE_READING);
384  } else {
385    EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
386  }
387}
388
389// When the server thread serving the clients is in the READING state,
390// try to get the result of the async read. If async read is done,
391// go into the READ_DONE state. For any problems, go into the
392// DISCONNECTING state.
393void CrashGenerationServer::HandleReadingState() {
394  assert(server_state_ == IPC_SERVER_STATE_READING);
395
396  DWORD bytes_count = 0;
397  bool success = GetOverlappedResult(pipe_,
398                                     &overlapped_,
399                                     &bytes_count,
400                                     FALSE) != FALSE;
401  DWORD error_code = success ? ERROR_SUCCESS : GetLastError();
402
403  if (success && bytes_count == sizeof(ProtocolMessage)) {
404    EnterStateImmediately(IPC_SERVER_STATE_READ_DONE);
405  } else {
406    // We should never get an I/O incomplete since we should not execute this
407    // unless the Read has finished and the overlapped event is signaled. If
408    // we do get INCOMPLETE, we have a bug in our code.
409    assert(error_code != ERROR_IO_INCOMPLETE);
410
411    EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
412  }
413}
414
415// When the server thread serving the client is in the READ_DONE state,
416// validate the client's request message, register the client by
417// creating appropriate objects and prepare the response.  Then try to
418// write the response to the pipe asynchronously. If that succeeds,
419// go into the WRITING state. For any problems, go into the DISCONNECTING
420// state.
421void CrashGenerationServer::HandleReadDoneState() {
422  assert(server_state_ == IPC_SERVER_STATE_READ_DONE);
423
424  if (!IsClientRequestValid(msg_)) {
425    EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
426    return;
427  }
428
429  if (msg_.tag == MESSAGE_TAG_UPLOAD_REQUEST) {
430    if (upload_request_callback_)
431      upload_request_callback_(upload_context_, msg_.id);
432    EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
433    return;
434  }
435
436  scoped_ptr<ClientInfo> client_info(
437      new ClientInfo(this,
438                     msg_.id,
439                     msg_.dump_type,
440                     msg_.thread_id,
441                     msg_.exception_pointers,
442                     msg_.assert_info,
443                     msg_.custom_client_info));
444
445  if (!client_info->Initialize()) {
446    EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
447    return;
448  }
449
450  // Issues an asynchronous WriteFile call if successful.
451  // Iff successful, assigns ownership of the client_info pointer to the server
452  // instance, in which case we must be sure not to free it in this function.
453  if (!RespondToClient(client_info.get())) {
454    EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
455    return;
456  }
457
458  client_info_ = client_info.release();
459
460  // Note that the asynchronous write issued by RespondToClient function
461  // can finish before  the code below executes. But it is okay to change
462  // state after issuing the asynchronous write. This is because even if
463  // the asynchronous write is done, the callback for it would not be
464  // executed until the current thread finishes its execution.
465  EnterStateWhenSignaled(IPC_SERVER_STATE_WRITING);
466}
467
468// When the server thread serving the clients is in the WRITING state,
469// try to get the result of the async write. If the async write is done,
470// go into the WRITE_DONE state. For any problems, go into the
471// DISONNECTING state.
472void CrashGenerationServer::HandleWritingState() {
473  assert(server_state_ == IPC_SERVER_STATE_WRITING);
474
475  DWORD bytes_count = 0;
476  bool success = GetOverlappedResult(pipe_,
477                                     &overlapped_,
478                                     &bytes_count,
479                                     FALSE) != FALSE;
480  DWORD error_code = success ? ERROR_SUCCESS : GetLastError();
481
482  if (success) {
483    EnterStateImmediately(IPC_SERVER_STATE_WRITE_DONE);
484    return;
485  }
486
487  // We should never get an I/O incomplete since we should not execute this
488  // unless the Write has finished and the overlapped event is signaled. If
489  // we do get INCOMPLETE, we have a bug in our code.
490  assert(error_code != ERROR_IO_INCOMPLETE);
491
492  EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
493}
494
495// When the server thread serving the clients is in the WRITE_DONE state,
496// try to issue an async read on the pipe. If the read completes synchronously
497// or if I/O is still pending then go into the READING_ACK state. For any
498// issues, go into the DISCONNECTING state.
499void CrashGenerationServer::HandleWriteDoneState() {
500  assert(server_state_ == IPC_SERVER_STATE_WRITE_DONE);
501
502  DWORD bytes_count = 0;
503  bool success = ReadFile(pipe_,
504                           &msg_,
505                           sizeof(msg_),
506                           &bytes_count,
507                           &overlapped_) != FALSE;
508  DWORD error_code = success ? ERROR_SUCCESS : GetLastError();
509
510  if (success) {
511    EnterStateImmediately(IPC_SERVER_STATE_READING_ACK);
512  } else if (error_code == ERROR_IO_PENDING) {
513    EnterStateWhenSignaled(IPC_SERVER_STATE_READING_ACK);
514  } else {
515    EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
516  }
517}
518
519// When the server thread serving the clients is in the READING_ACK state,
520// try to get result of async read. Go into the DISCONNECTING state.
521void CrashGenerationServer::HandleReadingAckState() {
522  assert(server_state_ == IPC_SERVER_STATE_READING_ACK);
523
524  DWORD bytes_count = 0;
525  bool success = GetOverlappedResult(pipe_,
526                                     &overlapped_,
527                                     &bytes_count,
528                                     FALSE) != FALSE;
529  DWORD error_code = success ? ERROR_SUCCESS : GetLastError();
530
531  if (success) {
532    // The connection handshake with the client is now complete; perform
533    // the callback.
534    if (connect_callback_) {
535      connect_callback_(connect_context_, client_info_);
536    }
537  } else {
538    // We should never get an I/O incomplete since we should not execute this
539    // unless the Read has finished and the overlapped event is signaled. If
540    // we do get INCOMPLETE, we have a bug in our code.
541    assert(error_code != ERROR_IO_INCOMPLETE);
542  }
543
544  EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
545}
546
547// When the server thread serving the client is in the DISCONNECTING state,
548// disconnect from the pipe and reset the event. If anything fails, go into
549// the ERROR state. If it goes well, go into the INITIAL state and set the
550// event to start all over again.
551void CrashGenerationServer::HandleDisconnectingState() {
552  assert(server_state_ == IPC_SERVER_STATE_DISCONNECTING);
553
554  // Done serving the client.
555  client_info_ = NULL;
556
557  overlapped_.Internal = NULL;
558  overlapped_.InternalHigh = NULL;
559  overlapped_.Offset = 0;
560  overlapped_.OffsetHigh = 0;
561  overlapped_.Pointer = NULL;
562
563  if (!ResetEvent(overlapped_.hEvent)) {
564    EnterErrorState();
565    return;
566  }
567
568  if (!DisconnectNamedPipe(pipe_)) {
569    EnterErrorState();
570    return;
571  }
572
573  // If the server is shutting down do not connect to the
574  // next client.
575  if (shutting_down_) {
576    return;
577  }
578
579  EnterStateImmediately(IPC_SERVER_STATE_INITIAL);
580}
581
582void CrashGenerationServer::EnterErrorState() {
583  SetEvent(overlapped_.hEvent);
584  server_state_ = IPC_SERVER_STATE_ERROR;
585}
586
587void CrashGenerationServer::EnterStateWhenSignaled(IPCServerState state) {
588  server_state_ = state;
589}
590
591void CrashGenerationServer::EnterStateImmediately(IPCServerState state) {
592  server_state_ = state;
593
594  if (!SetEvent(overlapped_.hEvent)) {
595    server_state_ = IPC_SERVER_STATE_ERROR;
596  }
597}
598
599bool CrashGenerationServer::PrepareReply(const ClientInfo& client_info,
600                                         ProtocolMessage* reply) const {
601  reply->tag = MESSAGE_TAG_REGISTRATION_RESPONSE;
602  reply->id = GetCurrentProcessId();
603
604  if (CreateClientHandles(client_info, reply)) {
605    return true;
606  }
607
608  if (reply->dump_request_handle) {
609    CloseHandle(reply->dump_request_handle);
610  }
611
612  if (reply->dump_generated_handle) {
613    CloseHandle(reply->dump_generated_handle);
614  }
615
616  if (reply->server_alive_handle) {
617    CloseHandle(reply->server_alive_handle);
618  }
619
620  return false;
621}
622
623bool CrashGenerationServer::CreateClientHandles(const ClientInfo& client_info,
624                                                ProtocolMessage* reply) const {
625  HANDLE current_process = GetCurrentProcess();
626  if (!DuplicateHandle(current_process,
627                       client_info.dump_requested_handle(),
628                       client_info.process_handle(),
629                       &reply->dump_request_handle,
630                       kDumpRequestEventAccess,
631                       FALSE,
632                       0)) {
633    return false;
634  }
635
636  if (!DuplicateHandle(current_process,
637                       client_info.dump_generated_handle(),
638                       client_info.process_handle(),
639                       &reply->dump_generated_handle,
640                       kDumpGeneratedEventAccess,
641                       FALSE,
642                       0)) {
643    return false;
644  }
645
646  if (!DuplicateHandle(current_process,
647                       server_alive_handle_,
648                       client_info.process_handle(),
649                       &reply->server_alive_handle,
650                       kMutexAccess,
651                       FALSE,
652                       0)) {
653    return false;
654  }
655
656  return true;
657}
658
659bool CrashGenerationServer::RespondToClient(ClientInfo* client_info) {
660  ProtocolMessage reply;
661  if (!PrepareReply(*client_info, &reply)) {
662    return false;
663  }
664
665  DWORD bytes_count = 0;
666  bool success = WriteFile(pipe_,
667                            &reply,
668                            sizeof(reply),
669                            &bytes_count,
670                            &overlapped_) != FALSE;
671  DWORD error_code = success ? ERROR_SUCCESS : GetLastError();
672
673  if (!success && error_code != ERROR_IO_PENDING) {
674    return false;
675  }
676
677  // Takes over ownership of client_info. We MUST return true if AddClient
678  // succeeds.
679  if (!AddClient(client_info)) {
680    return false;
681  }
682
683  return true;
684}
685
686// The server thread servicing the clients runs this method. The method
687// implements the state machine described in ReadMe.txt along with the
688// helper methods HandleXXXState.
689void CrashGenerationServer::HandleConnectionRequest() {
690  AutoCriticalSection lock(&sync_);
691
692  // If we are shutting doen then get into ERROR state, reset the event so more
693  // workers don't run and return immediately.
694  if (shutting_down_) {
695    server_state_ = IPC_SERVER_STATE_ERROR;
696    ResetEvent(overlapped_.hEvent);
697    return;
698  }
699
700  switch (server_state_) {
701    case IPC_SERVER_STATE_ERROR:
702      HandleErrorState();
703      break;
704
705    case IPC_SERVER_STATE_INITIAL:
706      HandleInitialState();
707      break;
708
709    case IPC_SERVER_STATE_CONNECTING:
710      HandleConnectingState();
711      break;
712
713    case IPC_SERVER_STATE_CONNECTED:
714      HandleConnectedState();
715      break;
716
717    case IPC_SERVER_STATE_READING:
718      HandleReadingState();
719      break;
720
721    case IPC_SERVER_STATE_READ_DONE:
722      HandleReadDoneState();
723      break;
724
725    case IPC_SERVER_STATE_WRITING:
726      HandleWritingState();
727      break;
728
729    case IPC_SERVER_STATE_WRITE_DONE:
730      HandleWriteDoneState();
731      break;
732
733    case IPC_SERVER_STATE_READING_ACK:
734      HandleReadingAckState();
735      break;
736
737    case IPC_SERVER_STATE_DISCONNECTING:
738      HandleDisconnectingState();
739      break;
740
741    default:
742      assert(false);
743      // This indicates that we added one more state without
744      // adding handling code.
745      server_state_ = IPC_SERVER_STATE_ERROR;
746      break;
747  }
748}
749
750bool CrashGenerationServer::AddClient(ClientInfo* client_info) {
751  HANDLE request_wait_handle = NULL;
752  if (!RegisterWaitForSingleObject(&request_wait_handle,
753                                   client_info->dump_requested_handle(),
754                                   OnDumpRequest,
755                                   client_info,
756                                   INFINITE,
757                                   kDumpRequestThreadFlags)) {
758    return false;
759  }
760
761  client_info->set_dump_request_wait_handle(request_wait_handle);
762
763  // OnClientEnd will be called when the client process terminates.
764  HANDLE process_wait_handle = NULL;
765  if (!RegisterWaitForSingleObject(&process_wait_handle,
766                                   client_info->process_handle(),
767                                   OnClientEnd,
768                                   client_info,
769                                   INFINITE,
770                                   WT_EXECUTEONLYONCE)) {
771    return false;
772  }
773
774  client_info->set_process_exit_wait_handle(process_wait_handle);
775
776  // New scope to hold the lock for the shortest time.
777  {
778    AutoCriticalSection lock(&sync_);
779    clients_.push_back(client_info);
780  }
781
782  return true;
783}
784
785// static
786void CALLBACK CrashGenerationServer::OnPipeConnected(void* context, BOOLEAN) {
787  assert(context);
788
789  CrashGenerationServer* obj =
790      reinterpret_cast<CrashGenerationServer*>(context);
791  obj->HandleConnectionRequest();
792}
793
794// static
795void CALLBACK CrashGenerationServer::OnDumpRequest(void* context, BOOLEAN) {
796  assert(context);
797  ClientInfo* client_info = reinterpret_cast<ClientInfo*>(context);
798  client_info->PopulateCustomInfo();
799
800  CrashGenerationServer* crash_server = client_info->crash_server();
801  assert(crash_server);
802  crash_server->HandleDumpRequest(*client_info);
803
804  ResetEvent(client_info->dump_requested_handle());
805}
806
807// static
808void CALLBACK CrashGenerationServer::OnClientEnd(void* context, BOOLEAN) {
809  assert(context);
810  ClientInfo* client_info = reinterpret_cast<ClientInfo*>(context);
811
812  CrashGenerationServer* crash_server = client_info->crash_server();
813  assert(crash_server);
814
815  client_info->UnregisterWaits();
816  InterlockedIncrement(&crash_server->cleanup_item_count_);
817
818  if (!QueueUserWorkItem(CleanupClient, context, WT_EXECUTEDEFAULT)) {
819    InterlockedDecrement(&crash_server->cleanup_item_count_);
820  }
821}
822
823// static
824DWORD WINAPI CrashGenerationServer::CleanupClient(void* context) {
825  assert(context);
826  ClientInfo* client_info = reinterpret_cast<ClientInfo*>(context);
827
828  CrashGenerationServer* crash_server = client_info->crash_server();
829  assert(crash_server);
830
831  if (crash_server->exit_callback_) {
832    crash_server->exit_callback_(crash_server->exit_context_, client_info);
833  }
834
835  crash_server->DoCleanup(client_info);
836
837  InterlockedDecrement(&crash_server->cleanup_item_count_);
838  return 0;
839}
840
841void CrashGenerationServer::DoCleanup(ClientInfo* client_info) {
842  assert(client_info);
843
844  // Start a new scope to release lock automatically.
845  {
846    AutoCriticalSection lock(&sync_);
847    clients_.remove(client_info);
848  }
849
850  delete client_info;
851}
852
853void CrashGenerationServer::HandleDumpRequest(const ClientInfo& client_info) {
854  // Generate the dump only if it's explicitly requested by the
855  // server application; otherwise the server might want to generate
856  // dump in the callback.
857  std::wstring dump_path;
858  if (generate_dumps_) {
859    if (!GenerateDump(client_info, &dump_path)) {
860      return;
861    }
862  }
863
864  if (dump_callback_) {
865    std::wstring* ptr_dump_path = (dump_path == L"") ? NULL : &dump_path;
866    dump_callback_(dump_context_, &client_info, ptr_dump_path);
867  }
868
869  SetEvent(client_info.dump_generated_handle());
870}
871
872bool CrashGenerationServer::GenerateDump(const ClientInfo& client,
873                                         std::wstring* dump_path) {
874  assert(client.pid() != 0);
875  assert(client.process_handle());
876
877  // We have to get the address of EXCEPTION_INFORMATION from
878  // the client process address space.
879  EXCEPTION_POINTERS* client_ex_info = NULL;
880  if (!client.GetClientExceptionInfo(&client_ex_info)) {
881    return false;
882  }
883
884  DWORD client_thread_id = 0;
885  if (!client.GetClientThreadId(&client_thread_id)) {
886    return false;
887  }
888
889  return dump_generator_->WriteMinidump(client.process_handle(),
890                                        client.pid(),
891                                        client_thread_id,
892                                        GetCurrentThreadId(),
893                                        client_ex_info,
894                                        client.assert_info(),
895                                        client.dump_type(),
896                                        true,
897                                        dump_path);
898}
899
900}  // namespace google_breakpad