use std::os::unix::net::UnixStream as StdUnixStream;
use std::u16;
use crate::address::Protocol;
use bytes::*;
use libc;
use std::os::unix::io::{FromRawFd, RawFd};
use tokio::io::{AsyncReadExt, AsyncWriteExt, BufReader};
use tokio::net::UnixStream;
use crate::management::interface::{Request, Response};
use crate::management::Error;
#[derive(Debug)]
pub struct ManagementStream(
BufReader<UnixStream>,
);
impl ManagementStream {
pub fn open() -> Result<Self, std::io::Error> {
let fd: RawFd = unsafe {
libc::socket(
libc::AF_BLUETOOTH,
libc::SOCK_RAW | libc::SOCK_CLOEXEC | libc::SOCK_NONBLOCK,
Protocol::HCI as libc::c_int,
)
};
if fd < 0 {
return Err(std::io::Error::last_os_error());
}
let addr = bluez_sys::sockaddr_hci {
hci_family: libc::AF_BLUETOOTH as u16,
hci_dev: bluez_sys::HCI_DEV_NONE as u16,
hci_channel: bluez_sys::HCI_CHANNEL_CONTROL as u16,
};
if unsafe {
libc::bind(
fd,
&addr as *const bluez_sys::sockaddr_hci as *const libc::sockaddr,
std::mem::size_of::<bluez_sys::sockaddr_hci>() as u32,
)
} < 0
{
let err = std::io::Error::last_os_error();
unsafe {
libc::close(fd);
}
return Err(err);
}
Ok(ManagementStream(BufReader::new(UnixStream::from_std(
unsafe { StdUnixStream::from_raw_fd(fd) },
)?)))
}
pub async fn send(&mut self, request: Request) -> Result<usize, std::io::Error> {
let buf: Bytes = request.into();
self.0.write(&buf).await
}
pub async fn receive(&mut self) -> Result<Response, Error> {
let mut header = [0u8; 6];
self.0.read_exact(&mut header).await?;
let param_size = u16::from_le_bytes([header[4], header[5]]) as usize;
let mut body = vec![0u8; param_size];
self.0.read_exact(&mut body[..]).await?;
Response::parse(Buf::chain(&header[..], &body[..]))
}
}