// Copyright (c) 2013 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.

#include "mist/usb_device_event_notifier.h"

#include <limits>

#include <base/bind.h>
#include <base/bind_helpers.h>
#include <base/logging.h>
#include <base/strings/string_number_conversions.h>
#include <base/strings/stringprintf.h>
#include <brillo/udev/udev.h>
#include <brillo/udev/udev_device.h>
#include <brillo/udev/udev_enumerate.h>
#include <brillo/udev/udev_monitor.h>

#include "mist/usb_device_event_observer.h"

namespace mist {

namespace {

const char kAttributeBusNumber[] = "busnum";
const char kAttributeDeviceAddress[] = "devnum";
const char kAttributeIdProduct[] = "idProduct";
const char kAttributeIdVendor[] = "idVendor";

}  // namespace

UsbDeviceEventNotifier::UsbDeviceEventNotifier(brillo::Udev* udev)
    : udev_(udev) {
  CHECK(udev_);
}

UsbDeviceEventNotifier::~UsbDeviceEventNotifier() = default;

bool UsbDeviceEventNotifier::Initialize() {
  udev_monitor_ = udev_->CreateMonitorFromNetlink("udev");
  if (!udev_monitor_) {
    LOG(ERROR) << "Could not create udev monitor.";
    return false;
  }

  if (!udev_monitor_->FilterAddMatchSubsystemDeviceType("usb", "usb_device")) {
    LOG(ERROR) << "Could not add udev monitor filter.";
    return false;
  }

  if (!udev_monitor_->EnableReceiving()) {
    LOG(ERROR) << "Could not enable udev monitoring.";
    return false;
  }

  int udev_monitor_fd = udev_monitor_->GetFileDescriptor();
  if (udev_monitor_fd == brillo::UdevMonitor::kInvalidFileDescriptor) {
    LOG(ERROR) << "Could not get udev monitor file descriptor.";
    return false;
  }

  udev_monitor_watcher_ = base::FileDescriptorWatcher::WatchReadable(
      udev_monitor_fd,
      base::BindRepeating(
          &UsbDeviceEventNotifier::OnUdevMonitorFileDescriptorReadable,
          base::Unretained(this)));
  if (!udev_monitor_watcher_) {
    LOG(ERROR) << "Could not watch udev monitor file descriptor.";
    return false;
  }

  return true;
}

bool UsbDeviceEventNotifier::ScanExistingDevices() {
  std::unique_ptr<brillo::UdevEnumerate> enumerate = udev_->CreateEnumerate();
  if (!enumerate || !enumerate->AddMatchSubsystem("usb") ||
      !enumerate->AddMatchProperty("DEVTYPE", "usb_device") ||
      !enumerate->ScanDevices()) {
    LOG(ERROR) << "Could not enumerate USB devices on the system.";
    return false;
  }

  for (std::unique_ptr<brillo::UdevListEntry> list_entry =
           enumerate->GetListEntry();
       list_entry; list_entry = list_entry->GetNext()) {
    std::string sys_path = ConvertNullToEmptyString(list_entry->GetName());

    std::unique_ptr<brillo::UdevDevice> device =
        udev_->CreateDeviceFromSysPath(sys_path.c_str());
    if (!device)
      continue;

    uint8_t bus_number;
    uint8_t device_address;
    uint16_t vendor_id;
    uint16_t product_id;
    if (!GetDeviceAttributes(device.get(), &bus_number, &device_address,
                             &vendor_id, &product_id))
      continue;

    for (UsbDeviceEventObserver& observer : observer_list_) {
      observer.OnUsbDeviceAdded(sys_path, bus_number, device_address, vendor_id,
                                product_id);
    }
  }
  return true;
}

void UsbDeviceEventNotifier::AddObserver(UsbDeviceEventObserver* observer) {
  CHECK(observer);

  observer_list_.AddObserver(observer);
}

void UsbDeviceEventNotifier::RemoveObserver(UsbDeviceEventObserver* observer) {
  CHECK(observer);

  observer_list_.RemoveObserver(observer);
}

void UsbDeviceEventNotifier::OnUdevMonitorFileDescriptorReadable() {
  VLOG(3) << "Udev file descriptor available for read.";

  std::unique_ptr<brillo::UdevDevice> device = udev_monitor_->ReceiveDevice();
  if (!device) {
    LOG(WARNING) << "Ignore device event with no associated udev device.";
    return;
  }

  VLOG(1) << base::StringPrintf(
      "udev (SysPath=%s, "
      "Node=%s, "
      "Subsystem=%s, "
      "DevType=%s, "
      "Action=%s, "
      "BusNumber=%s, "
      "DeviceAddress=%s, "
      "VendorId=%s, "
      "ProductId=%s)",
      device->GetSysPath(), device->GetDeviceNode(), device->GetSubsystem(),
      device->GetDeviceType(), device->GetAction(),
      device->GetSysAttributeValue(kAttributeBusNumber),
      device->GetSysAttributeValue(kAttributeDeviceAddress),
      device->GetSysAttributeValue(kAttributeIdVendor),
      device->GetSysAttributeValue(kAttributeIdProduct));

  std::string sys_path = ConvertNullToEmptyString(device->GetSysPath());
  if (sys_path.empty()) {
    LOG(WARNING) << "Ignore device event with no device sysfs path.";
    return;
  }

  std::string action = ConvertNullToEmptyString(device->GetAction());
  if (action == "add") {
    uint8_t bus_number;
    uint8_t device_address;
    uint16_t vendor_id;
    uint16_t product_id;
    if (!GetDeviceAttributes(device.get(), &bus_number, &device_address,
                             &vendor_id, &product_id)) {
      LOG(WARNING) << "Ignore device event of unidentifiable device.";
      return;
    }

    for (UsbDeviceEventObserver& observer : observer_list_) {
      observer.OnUsbDeviceAdded(sys_path, bus_number, device_address, vendor_id,
                                product_id);
    }
    return;
  }

  if (action == "remove") {
    for (UsbDeviceEventObserver& observer : observer_list_)
      observer.OnUsbDeviceRemoved(sys_path);
  }
}

// static
std::string UsbDeviceEventNotifier::ConvertNullToEmptyString(const char* str) {
  return str ? str : std::string();
}

// static
bool UsbDeviceEventNotifier::ConvertHexStringToUint16(const std::string& str,
                                                      uint16_t* value) {
  int temp_value = -1;
  if (str.size() != 4 || !base::HexStringToInt(str, &temp_value) ||
      temp_value < 0 || temp_value > std::numeric_limits<uint16_t>::max()) {
    return false;
  }

  *value = static_cast<uint16_t>(temp_value);
  return true;
}

// static
bool UsbDeviceEventNotifier::ConvertStringToUint8(const std::string& str,
                                                  uint8_t* value) {
  unsigned temp_value = 0;
  if (!base::StringToUint(str, &temp_value) ||
      temp_value > std::numeric_limits<uint8_t>::max()) {
    return false;
  }

  *value = static_cast<uint8_t>(temp_value);
  return true;
}

// static
bool UsbDeviceEventNotifier::GetDeviceAttributes(
    const brillo::UdevDevice* device,
    uint8_t* bus_number,
    uint8_t* device_address,
    uint16_t* vendor_id,
    uint16_t* product_id) {
  std::string bus_number_string = ConvertNullToEmptyString(
      device->GetSysAttributeValue(kAttributeBusNumber));
  if (!ConvertStringToUint8(bus_number_string, bus_number)) {
    LOG(WARNING) << "Invalid USB bus number '" << bus_number_string << "'.";
    return false;
  }

  std::string device_address_string = ConvertNullToEmptyString(
      device->GetSysAttributeValue(kAttributeDeviceAddress));
  if (!ConvertStringToUint8(device_address_string, device_address)) {
    LOG(WARNING) << "Invalid USB device address '" << device_address_string
                 << "'.";
    return false;
  }

  std::string vendor_id_string = ConvertNullToEmptyString(
      device->GetSysAttributeValue(kAttributeIdVendor));
  if (!ConvertHexStringToUint16(vendor_id_string, vendor_id)) {
    LOG(WARNING) << "Invalid USB vendor ID '" << vendor_id_string << "'.";
    return false;
  }

  std::string product_id_string = ConvertNullToEmptyString(
      device->GetSysAttributeValue(kAttributeIdProduct));
  if (!ConvertHexStringToUint16(product_id_string, product_id)) {
    LOG(WARNING) << "Invalid USB product ID '" << product_id_string << "'.";
    return false;
  }

  return true;
}

}  // namespace mist
