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