use crate::BTPROTO_HCI;
use crate::{HciSocketAddr, ToHciSocketAddr};
use fd::FileDesc;
use libc::{c_int, AF_BLUETOOTH, SOCK_CLOEXEC, SOCK_NONBLOCK, SOCK_RAW};
use std::io;
use std::os::unix::io::{AsRawFd, RawFd};
pub struct HciSocket(FileDesc);
impl HciSocket {
pub fn bind(addr: HciSocketAddr) -> io::Result<HciSocket> {
unsafe {
let fd: c_int = libc::socket(
AF_BLUETOOTH,
SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
BTPROTO_HCI,
);
if fd == -1 {
return Err(io::Error::last_os_error());
}
let a = addr.to_socket_addr();
match libc::bind(fd, &libc::sockaddr::from(a), 0x5) {
-1 => Err(io::Error::last_os_error()),
_ => Ok(HciSocket(FileDesc::new(fd, true))),
}
}
}
pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
match unsafe {
libc::write(
self.as_raw_fd(),
buf.as_ptr() as *const libc::c_void,
buf.len(),
)
} {
-1 => Err(io::Error::last_os_error()),
r => Ok(r as usize),
}
}
pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
match unsafe {
libc::read(
self.as_raw_fd(),
buf.as_mut_ptr() as *mut libc::c_void,
buf.len(),
)
} {
-1 => Err(io::Error::last_os_error()),
r => Ok(r as usize),
}
}
}
impl AsRawFd for HciSocket {
fn as_raw_fd(&self) -> RawFd {
self.0.as_raw_fd()
}
}