text: // Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #ifndef DEBUGD_SRC_PACKET_CAPTURE_TOOL_H_
  #define DEBUGD_SRC_PACKET_CAPTURE_TOOL_H_
  
  #include <algorithm>
  #include <map>
  #include <memory>
  #include <string>
  #include <utility>
  
  #include <base/files/file_descriptor_watcher_posix.h>
  #include <base/files/file_util.h>
  #include <base/macros.h>
  #include <brillo/errors/error.h>
  #include <brillo/variant_dictionary.h>
  
  #include "debugd/src/subprocess_tool.h"
  
  namespace debugd {
  
  class PacketCaptureTool : public SubprocessTool {
   public:
    PacketCaptureTool() = default;
    PacketCaptureTool(const PacketCaptureTool&) = delete;
    PacketCaptureTool& operator=(const PacketCaptureTool&) = delete;
  
    ~PacketCaptureTool() override = default;
  
    // Starts packet capture if the given options are valid. Runs
    // `on_packet_capture_stopped` when the started packet capture process is
    // stopped or terminated.
    bool Start(bool is_dev_mode,
               const base::ScopedFD& status_fd,
               const base::ScopedFD& output_fd,
               const brillo::VariantDictionary& options,
               std::string* out_id,
               base::OnceClosure on_packet_capture_stopped,
               brillo::ErrorPtr* error);
  
    // Returns false if there are no ongoing packet capture processes.
    bool HasActivePacketCaptureProcess();
  
   private:
    struct ChildProcessInfo {
      ChildProcessInfo(base::ScopedFD pipe_read_fd_in,
                       std::unique_ptr<base::FileDescriptorWatcher::Controller>
                           pipe_read_watcher_in,
                       base::OnceClosure on_stopped_callback_in)
          : pipe_read_fd(std::move(pipe_read_fd_in)),
            pipe_read_watcher(std::move(pipe_read_watcher_in)),
            on_stopped_callback(std::move(on_stopped_callback_in)) {}
      ~ChildProcessInfo() = default;
  
      // Move constructor.
      ChildProcessInfo(ChildProcessInfo&& info) {
        pipe_read_fd = std::move(info.pipe_read_fd);
        pipe_read_watcher = std::move(info.pipe_read_watcher);
        on_stopped_callback = std::move(info.on_stopped_callback);
      }
  
      // Delete the copy constructor.
      ChildProcessInfo(const ChildProcessInfo& child) = delete;
  
      // The pipe that'll be used to read the status update of the child process.
      base::ScopedFD pipe_read_fd;
      // FileDescriptorWatcher will watch the readable state of the pipe to detect
      // when the child process has ended.
      std::unique_ptr<base::FileDescriptorWatcher::Controller> pipe_read_watcher;
      // The callback that will be run the packet capture process terminates.
      base::OnceClosure on_stopped_callback;
    };
  
    debugd::ProcessWithId* CreateCaptureProcessForFrequencyBasedCapture(
        const brillo::VariantDictionary& options,
        int output_fd,
        brillo::ErrorPtr* error);
    debugd::ProcessWithId* CreateCaptureProcessForDeviceBasedCapture(
        const brillo::VariantDictionary& options,
        int output_fd,
        brillo::ErrorPtr* error);
  
    // Is called when a packet capture helper process has terminated. Checks the
    // ChildProcessInfo of the process with pid `process_handle` and runs
    // `on_packet_capture_stopped_callback`. Sets `hasPacketCaptureRunning_` to
    // false if there are no packet capture processes left running.
    void OnPacketCaptureStopped(std::string process_handle);
  
    // ProcessWithId::id() -> ChildProcessInfo.
    std::map<std::string, ChildProcessInfo> helper_processes_;
  };
  
  }  // namespace debugd
  
  #endif  // DEBUGD_SRC_PACKET_CAPTURE_TOOL_H_
  