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