use futures::ready;
use libc::{
c_int, AF_BLUETOOTH, EAGAIN, EINPROGRESS, MSG_PEEK, SHUT_RD, SHUT_RDWR, SHUT_WR, SOCK_RAW, SOCK_STREAM,
SOL_BLUETOOTH, SOL_SOCKET, SO_ERROR, SO_RCVBUF, TIOCINQ, TIOCOUTQ,
};
use num_derive::{FromPrimitive, ToPrimitive};
use num_traits::FromPrimitive;
use std::{
convert::{TryFrom, TryInto},
fmt,
io::{Error, ErrorKind, Result},
mem::ManuallyDrop,
net::Shutdown,
os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd},
pin::Pin,
str::FromStr,
sync::Arc,
task::{Context, Poll},
};
use tokio::io::{unix::AsyncFd, AsyncRead, AsyncWrite, ReadBuf};
#[cfg(feature = "bluetoothd")]
pub(crate) mod profile;
#[cfg(feature = "bluetoothd")]
pub use profile::{ConnectRequest, Profile, ProfileHandle, ReqError, ReqResult, Role};
use crate::{
sock::{self, OwnedFd},
sys::{
bt_security, rfcomm_dev_req, sockaddr_rc, BTPROTO_RFCOMM, BT_SECURITY, BT_SECURITY_HIGH, BT_SECURITY_LOW,
BT_SECURITY_MEDIUM, BT_SECURITY_SDP, RFCOMMCREATEDEV, RFCOMMRELEASEDEV, RFCOMM_CONNINFO, RFCOMM_LM,
RFCOMM_LM_MASTER, RFCOMM_RELEASE_ONHUP, RFCOMM_REUSE_DLC, SOL_RFCOMM,
},
Address,
};
pub use crate::sys::rfcomm_conninfo as ConnInfo;
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SocketAddr {
pub addr: Address,
pub channel: u8,
}
impl SocketAddr {
pub const fn new(addr: Address, channel: u8) -> Self {
Self { addr, channel }
}
pub const fn any() -> Self {
Self { addr: Address::any(), channel: 0 }
}
}
impl fmt::Display for SocketAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "[{}]:{}", self.addr, self.channel)
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct InvalidSocketAddr(pub String);
impl fmt::Display for InvalidSocketAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "invalid RFCOMM socket address: {}", &self.0)
}
}
impl std::error::Error for InvalidSocketAddr {}
impl FromStr for SocketAddr {
type Err = InvalidSocketAddr;
fn from_str(s: &str) -> std::result::Result<Self, InvalidSocketAddr> {
let err = || InvalidSocketAddr(s.to_string());
let (addr, channel) = s.rsplit_once(':').ok_or_else(err)?;
let addr = addr.strip_prefix('[').and_then(|s| s.strip_suffix(']')).ok_or_else(err)?;
Ok(Self { addr: addr.parse().map_err(|_| err())?, channel: channel.parse().map_err(|_| err())? })
}
}
impl sock::SysSockAddr for SocketAddr {
type SysSockAddr = sockaddr_rc;
fn into_sys_sock_addr(self) -> Self::SysSockAddr {
sockaddr_rc { rc_family: AF_BLUETOOTH as _, rc_bdaddr: self.addr.into(), rc_channel: self.channel }
}
fn try_from_sys_sock_addr(saddr: Self::SysSockAddr) -> Result<Self> {
if saddr.rc_family != AF_BLUETOOTH as _ {
return Err(Error::new(ErrorKind::InvalidInput, "sockaddr_rc::rc_family is not AF_BLUETOOTH"));
}
Ok(Self { addr: Address::from(saddr.rc_bdaddr), channel: saddr.rc_channel })
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, FromPrimitive, ToPrimitive)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum SecurityLevel {
Sdp = BT_SECURITY_SDP as _,
Low = BT_SECURITY_LOW as _,
Medium = BT_SECURITY_MEDIUM as _,
High = BT_SECURITY_HIGH as _,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Security {
pub level: SecurityLevel,
pub key_size: u8,
}
impl From<Security> for bt_security {
fn from(s: Security) -> Self {
bt_security { level: s.level as _, key_size: s.key_size }
}
}
impl TryFrom<bt_security> for Security {
type Error = Error;
fn try_from(value: bt_security) -> Result<Self> {
Ok(Self {
level: SecurityLevel::from_u8(value.level)
.ok_or_else(|| Error::new(ErrorKind::InvalidInput, "invalid bt_security::level"))?,
key_size: value.key_size,
})
}
}
pub struct Socket {
fd: AsyncFd<OwnedFd>,
}
impl fmt::Debug for Socket {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Socket").field("fd", &self.fd.as_raw_fd()).finish()
}
}
impl Socket {
pub fn new() -> Result<Self> {
Ok(Self { fd: AsyncFd::new(sock::socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)?)? })
}
pub fn listen(self, backlog: u32) -> Result<Listener> {
sock::listen(
self.fd.get_ref(),
backlog.try_into().map_err(|_| Error::new(ErrorKind::InvalidInput, "invalid backlog"))?,
)?;
Ok(Listener { socket: self })
}
pub async fn connect(self, sa: SocketAddr) -> Result<Stream> {
self.connect_priv(sa).await?;
Stream::from_socket(self)
}
pub fn bind(&self, sa: SocketAddr) -> Result<()> {
sock::bind(self.fd.get_ref(), sa)
}
pub fn local_addr(&self) -> Result<SocketAddr> {
sock::getsockname(self.fd.get_ref())
}
fn peer_addr_priv(&self) -> Result<SocketAddr> {
sock::getpeername(self.fd.get_ref())
}
pub fn security(&self) -> Result<Security> {
let bts: bt_security = sock::getsockopt(self.fd.get_ref(), SOL_BLUETOOTH, BT_SECURITY)?;
Security::try_from(bts)
}
pub fn set_security(&self, security: Security) -> Result<()> {
let bts: bt_security = security.into();
sock::setsockopt(self.fd.get_ref(), SOL_BLUETOOTH, BT_SECURITY, &bts)
}
pub fn recv_buffer(&self) -> Result<i32> {
sock::getsockopt(self.fd.get_ref(), SOL_SOCKET, SO_RCVBUF)
}
pub fn set_recv_buffer(&self, recv_buffer: i32) -> Result<()> {
sock::setsockopt(self.fd.get_ref(), SOL_SOCKET, SO_RCVBUF, &recv_buffer)
}
pub fn conn_info(&self) -> Result<ConnInfo> {
sock::getsockopt(self.fd.get_ref(), SOL_RFCOMM, RFCOMM_CONNINFO)
}
pub fn is_master(&self) -> Result<bool> {
let opt: u32 = sock::getsockopt(self.fd.get_ref(), SOL_RFCOMM, RFCOMM_LM)?;
Ok((opt & RFCOMM_LM_MASTER) != 0)
}
pub fn set_master(&self, master: bool) -> Result<()> {
let mut opt: u32 = sock::getsockopt(self.fd.get_ref(), SOL_RFCOMM, RFCOMM_LM)?;
if master {
opt |= RFCOMM_LM_MASTER;
} else {
opt &= !RFCOMM_LM_MASTER;
}
sock::setsockopt(self.fd.get_ref(), SOL_RFCOMM, RFCOMM_LM, &opt)
}
pub fn input_buffer(&self) -> Result<u32> {
let value: c_int = sock::ioctl_read(self.fd.get_ref(), TIOCINQ)?;
Ok(value as _)
}
pub fn output_buffer(&self) -> Result<u32> {
let value: c_int = sock::ioctl_read(self.fd.get_ref(), TIOCOUTQ)?;
Ok(value as _)
}
pub fn create_tty(&self, dev_id: i16) -> Result<i16> {
let local_addr = self.local_addr()?;
let remote_addr = self.peer_addr_priv()?;
let req = rfcomm_dev_req {
dev_id,
flags: RFCOMM_REUSE_DLC | RFCOMM_RELEASE_ONHUP,
src: local_addr.addr.into(),
dst: remote_addr.addr.into(),
channel: local_addr.channel,
};
let id: c_int = sock::ioctl_write(self.fd.get_ref(), RFCOMMCREATEDEV, &req)?;
Ok(id as i16)
}
pub fn release_tty(dev_id: i16) -> Result<()> {
let ctl_fd = AsyncFd::new(sock::socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_RFCOMM)?)?;
let req = rfcomm_dev_req { dev_id, flags: RFCOMM_REUSE_DLC | RFCOMM_RELEASE_ONHUP, ..Default::default() };
sock::ioctl_write(ctl_fd.get_ref(), RFCOMMRELEASEDEV, &req)?;
Ok(())
}
pub unsafe fn from_raw_fd(fd: RawFd) -> Result<Self> {
Ok(Self { fd: AsyncFd::new(OwnedFd::new(fd))? })
}
fn from_owned_fd(fd: OwnedFd) -> Result<Self> {
Ok(Self { fd: AsyncFd::new(fd)? })
}
sock_priv!();
}
impl AsRawFd for Socket {
fn as_raw_fd(&self) -> RawFd {
self.fd.as_raw_fd()
}
}
impl IntoRawFd for Socket {
fn into_raw_fd(self) -> RawFd {
self.fd.into_inner().into_raw_fd()
}
}
impl FromRawFd for Socket {
unsafe fn from_raw_fd(fd: RawFd) -> Self {
Self::from_raw_fd(fd).expect("from_raw_fd failed")
}
}
#[derive(Debug)]
pub struct Listener {
socket: Socket,
}
impl Listener {
pub async fn bind(sa: SocketAddr) -> Result<Self> {
let socket = Socket::new()?;
socket.bind(sa)?;
socket.listen(1)
}
pub async fn accept(&self) -> Result<(Stream, SocketAddr)> {
let (socket, sa) = self.socket.accept_priv().await?;
Ok((Stream::from_socket(socket)?, sa))
}
pub fn poll_accept(&self, cx: &mut Context) -> Poll<Result<(Stream, SocketAddr)>> {
let (socket, sa) = ready!(self.socket.poll_accept_priv(cx))?;
Poll::Ready(Ok((Stream::from_socket(socket)?, sa)))
}
pub unsafe fn from_raw_fd(fd: RawFd) -> Result<Self> {
Ok(Self { socket: Socket::from_raw_fd(fd)? })
}
}
impl AsRef<Socket> for Listener {
fn as_ref(&self) -> &Socket {
&self.socket
}
}
impl AsRawFd for Listener {
fn as_raw_fd(&self) -> RawFd {
self.socket.as_raw_fd()
}
}
impl FromRawFd for Listener {
unsafe fn from_raw_fd(fd: RawFd) -> Self {
Self::from_raw_fd(fd).expect("from_raw_fd failed")
}
}
#[derive(Debug)]
pub struct Stream {
socket: Socket,
}
impl Stream {
fn from_socket(socket: Socket) -> Result<Self> {
Ok(Self { socket })
}
pub async fn connect(addr: SocketAddr) -> Result<Self> {
let socket = Socket::new()?;
socket.bind(SocketAddr::any())?;
socket.connect(addr).await
}
pub fn peer_addr(&self) -> Result<SocketAddr> {
self.socket.peer_addr_priv()
}
pub async fn peek(&self, buf: &mut [u8]) -> Result<usize> {
self.socket.peek_priv(buf).await
}
pub fn poll_peek(&self, cx: &mut Context, buf: &mut ReadBuf) -> Poll<Result<usize>> {
self.socket.poll_peek_priv(cx, buf)
}
#[allow(clippy::needless_lifetimes)]
pub fn split<'a>(&'a mut self) -> (stream::ReadHalf<'a>, stream::WriteHalf<'a>) {
(stream::ReadHalf(self), stream::WriteHalf(self))
}
pub fn into_split(self) -> (stream::OwnedReadHalf, stream::OwnedWriteHalf) {
let stream = Arc::new(self);
let r = stream::OwnedReadHalf {
stream: ManuallyDrop::new(stream.clone()),
shutdown_on_drop: true,
drop: true,
};
let w = stream::OwnedWriteHalf { stream, shutdown_on_drop: true };
(r, w)
}
fn poll_write_priv(&self, cx: &mut Context, buf: &[u8]) -> Poll<Result<usize>> {
self.socket.poll_send_priv(cx, buf)
}
pub unsafe fn from_raw_fd(fd: RawFd) -> Result<Self> {
Self::from_socket(Socket::from_raw_fd(fd)?)
}
}
impl AsRef<Socket> for Stream {
fn as_ref(&self) -> &Socket {
&self.socket
}
}
impl AsRawFd for Stream {
fn as_raw_fd(&self) -> RawFd {
self.socket.as_raw_fd()
}
}
impl FromRawFd for Stream {
unsafe fn from_raw_fd(fd: RawFd) -> Self {
Self::from_raw_fd(fd).expect("from_raw_fd failed")
}
}
impl AsyncRead for Stream {
fn poll_read(self: Pin<&mut Self>, cx: &mut Context, buf: &mut ReadBuf) -> Poll<Result<()>> {
self.socket.poll_recv_priv(cx, buf)
}
}
impl AsyncWrite for Stream {
fn poll_write(self: Pin<&mut Self>, cx: &mut Context, buf: &[u8]) -> Poll<Result<usize>> {
self.poll_write_priv(cx, buf)
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Result<()>> {
self.socket.poll_flush_priv(cx)
}
fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Result<()>> {
self.socket.poll_shutdown_priv(cx, Shutdown::Write)
}
}
#[allow(clippy::duplicate_mod)]
#[path = "../stream_util.rs"]
pub mod stream;