use libusb;
use std::{
fmt::{self, Debug},
time::Duration,
};
use super::{UsbAdapter, UsbTimeout, YUBIHSM2_BULK_IN_ENDPOINT, YUBIHSM2_INTERFACE_NUM};
use adapter::AdapterError;
use securechannel::MAX_MSG_SIZE;
use serial_number::SerialNumber;
pub struct HsmDevice {
pub(super) device: libusb::Device<'static>,
pub product_name: String,
pub serial_number: SerialNumber,
}
impl HsmDevice {
pub(super) fn new(
device: libusb::Device<'static>,
product_name: String,
serial_number: SerialNumber,
) -> Self {
Self {
serial_number,
product_name,
device,
}
}
pub fn open(self, timeout: UsbTimeout) -> Result<UsbAdapter, AdapterError> {
let adapter = UsbAdapter::new(self, timeout)?;
info!(
"USB(bus={},addr={}): successfully opened {} (serial #{})",
adapter.device().bus_number(),
adapter.device().address(),
adapter.device().product_name.as_str(),
adapter.device().serial_number.as_str(),
);
Ok(adapter)
}
pub fn bus_number(&self) -> u8 {
self.device.bus_number()
}
pub fn address(&self) -> u8 {
self.device.address()
}
pub(super) fn open_handle(&self) -> Result<libusb::DeviceHandle<'static>, AdapterError> {
let mut handle = self.device.open()?;
handle.reset()?;
handle.claim_interface(YUBIHSM2_INTERFACE_NUM)?;
flush(&mut handle)?;
Ok(handle)
}
}
impl Debug for HsmDevice {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"HsmDevice(bus={} addr={} serial=#{})",
self.bus_number(),
self.address(),
self.serial_number,
)
}
}
fn flush(handle: &mut libusb::DeviceHandle) -> Result<(), AdapterError> {
let mut buffer = [0u8; MAX_MSG_SIZE];
let timeout = Duration::from_millis(1);
match handle.read_bulk(YUBIHSM2_BULK_IN_ENDPOINT, &mut buffer, timeout) {
Ok(_) | Err(libusb::Error::Timeout) => Ok(()),
Err(e) => Err(e.into()),
}
}