// Copyright (c) 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_
#define CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_

#include <windows.h>
#include <dbghelp.h>
#include <string>
#include <utility>
#include "windows/common/ipc_protocol.h"
#include "common/scoped_ptr.h"

namespace google_breakpad {

struct CustomClientInfo;

// Abstraction of client-side implementation of out of process
// crash generation.
//
// The process that desires to have out-of-process crash dump
// generation service can use this class in the following way:
//
// * Create an instance.
// * Call Register method so that the client tries to register
//   with the server process and check the return value. If
//   registration is not successful, out-of-process crash dump
//   generation will not be available
// * Request dump generation by calling either of the two
//   overloaded RequestDump methods - one in case of exceptions
//   and the other in case of assertion failures
//
// Note that it is the responsibility of the client code of
// this class to set the unhandled exception filter with the
// system by calling the SetUnhandledExceptionFilter function
// and the client code should explicitly request dump generation.
class CrashGenerationClient {
 public:
  CrashGenerationClient(const wchar_t* pipe_name,
                        MINIDUMP_TYPE dump_type,
                        const CustomClientInfo* custom_info);

  CrashGenerationClient(HANDLE pipe_handle,
                        MINIDUMP_TYPE dump_type,
                        const CustomClientInfo* custom_info);

  ~CrashGenerationClient();

  // Registers the client process with the crash server.
  //
  // Returns true if the registration is successful; false otherwise.
  bool Register();

  // Requests the crash server to upload a previous dump with the
  // given crash id.
  bool RequestUpload(DWORD crash_id);

  bool RequestDump(EXCEPTION_POINTERS* ex_info,
                   MDRawAssertionInfo* assert_info);

  // Requests the crash server to generate a dump with the given
  // exception information.
  //
  // Returns true if the dump was successful; false otherwise. Note that
  // if the registration step was not performed or it was not successful,
  // false will be returned.
  bool RequestDump(EXCEPTION_POINTERS* ex_info);

  // Requests the crash server to generate a dump with the given
  // assertion information.
  //
  // Returns true if the dump was successful; false otherwise. Note that
  // if the registration step was not performed or it was not successful,
  // false will be returned.
  bool RequestDump(MDRawAssertionInfo* assert_info);

  // If the crash generation client is running in a sandbox that prevents it
  // from opening the named pipe directly, the server process may open the
  // handle and duplicate it into the client process with this helper method.
  // Returns INVALID_HANDLE_VALUE on failure. The process must have been opened
  // with the PROCESS_DUP_HANDLE access right.
  static HANDLE DuplicatePipeToClientProcess(const wchar_t* pipe_name,
                                             HANDLE hProcess);

 private:
  // Represents the state of this client with regards to the server.
  enum RegistrationState {
    // We haven't attempted to register with the server yet.
    UNREGISTERED,

    // Registration is pending.
    REGISTERING,

    // We successfully registered with the server
    REGISTERED,

    // We attempted to register with the server but failed.
    FAILED,
  };

  // Registration function that will be run in a separate thread.
  static DWORD NTAPI AsyncRegister(LPVOID param);

  // Connects to the appropriate pipe and sets the pipe handle state.
  //
  // Returns the pipe handle if everything goes well; otherwise Returns NULL.
  HANDLE ConnectToServer();

  // Performs a handshake with the server over the given pipe which should be
  // already connected to the server.
  //
  // Returns true if handshake with the server was successful; false otherwise.
  bool RegisterClient(HANDLE pipe);

  // Validates the given server response.
  bool ValidateResponse(const ProtocolMessage& msg) const;

  // Waits until registration is complete and returns true if the registration
  // step succeeded; false otherwise.
  bool WaitForRegistration();

  // Thread-safe function to set the registration state.
  void SetRegistrationState(RegistrationState state);

  // Connects to the given named pipe with given parameters.
  //
  // Returns true if the connection is successful; false otherwise.
  HANDLE ConnectToPipe(const wchar_t* pipe_name,
                       DWORD pipe_access,
                       DWORD flags_attrs);

  // Signals the crash event and wait for the server to generate crash.
  bool SignalCrashEventAndWait();

  // Sync object for thread-safe access to the state.
  CRITICAL_SECTION sync_;

  // State of the registration process.
  RegistrationState state_;

  // Pipe name to use to talk to server.
  std::wstring pipe_name_;

  // Pipe handle duplicated from server process. Only valid before
  // Register is called.
  HANDLE pipe_handle_;

  // Custom client information
  CustomClientInfo custom_info_;

  // Type of dump to generate.
  MINIDUMP_TYPE dump_type_;

  // Event to signal in case of a crash.
  HANDLE crash_event_;

  // Handle to wait on after signaling a crash for the server
  // to finish generating crash dump.
  HANDLE crash_generated_;

  // Handle to a mutex that will become signaled with WAIT_ABANDONED
  // if the server process goes down.
  HANDLE server_alive_;

  // Server process id.
  DWORD server_process_id_;

  // Id of the thread that caused the crash.
  DWORD thread_id_;

  // Exception pointers for an exception crash.
  EXCEPTION_POINTERS* exception_pointers_;

  // Assertion info for an invalid parameter or pure call crash.
  MDRawAssertionInfo assert_info_;

  // Disable copy ctor and operator=.
  CrashGenerationClient(const CrashGenerationClient& crash_client);
  CrashGenerationClient& operator=(const CrashGenerationClient& crash_client);
};

}  // namespace google_breakpad

#endif  // CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_
