blob: 9d20012fa506e460e23b446d78ab08576f7c7605 [file] [log] [blame]
use num_traits::cast::{FromPrimitive, ToPrimitive};
use std::os::raw::c_char;
use std::sync::{Arc, Mutex};
use std::vec::Vec;
use crate::bindings::root as bindings;
use crate::btif::{
ascii_to_string, ptr_to_vec, BluetoothInterface, BtStatus, FfiAddress, RawAddress,
SupportedProfiles, Uuid,
};
use crate::topstack::get_dispatchers;
use crate::{cast_to_ffi_address, ccall, deref_const_ffi_address};
use topshim_macros::cb_variant;
#[derive(Clone, Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
#[repr(u32)]
pub enum BtSdpType {
Raw = 0,
MapMas,
MapMns,
PbapPse,
PbapPce,
OppServer,
SapServer,
Dip,
}
impl From<bindings::bluetooth_sdp_types> for BtSdpType {
fn from(item: bindings::bluetooth_sdp_types) -> Self {
BtSdpType::from_u32(item).unwrap_or(BtSdpType::Raw)
}
}
#[derive(Clone, Debug)]
pub struct BtSdpHeader {
sdp_type: BtSdpType,
uuid: Uuid,
service_name_length: u32,
service_name: String,
rfcomm_channel_number: i32,
l2cap_psm: i32,
profile_version: i32,
}
impl From<bindings::_bluetooth_sdp_hdr> for BtSdpHeader {
fn from(item: bindings::_bluetooth_sdp_hdr) -> Self {
let service_name = ascii_to_string(
unsafe {
std::slice::from_raw_parts(
item.service_name as *const u8,
item.service_name_length as usize,
)
},
item.service_name_length as usize,
);
BtSdpHeader {
sdp_type: BtSdpType::from(item.type_),
uuid: item.uuid,
service_name_length: item.service_name_length,
service_name,
rfcomm_channel_number: item.rfcomm_channel_number,
l2cap_psm: item.l2cap_psm,
profile_version: item.profile_version,
}
}
}
#[derive(Clone, Debug)]
pub struct BtSdpHeaderOverlay {
hdr: BtSdpHeader,
user1_len: i32,
user1_data: Vec<u8>,
user2_len: i32,
user2_data: Vec<u8>,
}
impl From<bindings::_bluetooth_sdp_hdr_overlay> for BtSdpHeaderOverlay {
fn from(item: bindings::_bluetooth_sdp_hdr_overlay) -> Self {
let user1_len = item.user1_ptr_len;
let user1_data = unsafe {
std::slice::from_raw_parts(item.user1_ptr, item.user1_ptr_len as usize).to_vec()
};
let user2_len = item.user2_ptr_len;
let user2_data = unsafe {
std::slice::from_raw_parts(item.user2_ptr, item.user2_ptr_len as usize).to_vec()
};
BtSdpHeaderOverlay {
hdr: unsafe {
BtSdpHeader::from(
*((&item as *const bindings::_bluetooth_sdp_hdr_overlay)
as *const bindings::_bluetooth_sdp_hdr),
)
},
user1_len,
user1_data,
user2_len,
user2_data,
}
}
}
#[derive(Clone, Debug)]
pub struct BtSdpMasRecord {
hdr: BtSdpHeaderOverlay,
mas_instance_id: u32,
supported_features: u32,
supported_message_types: u32,
}
impl From<bindings::_bluetooth_sdp_mas_record> for BtSdpMasRecord {
fn from(item: bindings::_bluetooth_sdp_mas_record) -> Self {
BtSdpMasRecord {
hdr: BtSdpHeaderOverlay::from(item.hdr),
mas_instance_id: item.mas_instance_id,
supported_features: item.supported_features,
supported_message_types: item.supported_message_types,
}
}
}
#[derive(Clone, Debug)]
pub struct BtSdpMnsRecord {
hdr: BtSdpHeaderOverlay,
supported_features: u32,
}
impl From<bindings::_bluetooth_sdp_mns_record> for BtSdpMnsRecord {
fn from(item: bindings::_bluetooth_sdp_mns_record) -> Self {
BtSdpMnsRecord {
hdr: BtSdpHeaderOverlay::from(item.hdr),
supported_features: item.supported_features,
}
}
}
#[derive(Clone, Debug)]
pub struct BtSdpPseRecord {
hdr: BtSdpHeaderOverlay,
supported_features: u32,
supported_repositories: u32,
}
impl From<bindings::_bluetooth_sdp_pse_record> for BtSdpPseRecord {
fn from(item: bindings::_bluetooth_sdp_pse_record) -> Self {
BtSdpPseRecord {
hdr: BtSdpHeaderOverlay::from(item.hdr),
supported_features: item.supported_features,
supported_repositories: item.supported_repositories,
}
}
}
#[derive(Clone, Debug)]
pub struct BtSdpPceRecord {
hdr: BtSdpHeaderOverlay,
}
impl From<bindings::_bluetooth_sdp_pce_record> for BtSdpPceRecord {
fn from(item: bindings::_bluetooth_sdp_pce_record) -> Self {
BtSdpPceRecord { hdr: BtSdpHeaderOverlay::from(item.hdr) }
}
}
#[derive(Clone, Debug)]
pub struct BtSdpOpsRecord {
hdr: BtSdpHeaderOverlay,
supported_formats_list_len: i32,
supported_formats_list: [u8; 15usize],
}
impl From<bindings::_bluetooth_sdp_ops_record> for BtSdpOpsRecord {
fn from(item: bindings::_bluetooth_sdp_ops_record) -> Self {
BtSdpOpsRecord {
hdr: BtSdpHeaderOverlay::from(item.hdr),
supported_formats_list_len: item.supported_formats_list_len,
supported_formats_list: item.supported_formats_list,
}
}
}
#[derive(Clone, Debug)]
pub struct BtSdpSapRecord {
hdr: BtSdpHeaderOverlay,
}
impl From<bindings::_bluetooth_sdp_sap_record> for BtSdpSapRecord {
fn from(item: bindings::_bluetooth_sdp_sap_record) -> Self {
BtSdpSapRecord { hdr: BtSdpHeaderOverlay::from(item.hdr) }
}
}
#[derive(Clone, Debug)]
pub struct BtSdpDipRecord {
hdr: BtSdpHeaderOverlay,
spec_id: u16,
vendor: u16,
vendor_id_source: u16,
product: u16,
version: u16,
primary_record: bool,
}
impl From<bindings::_bluetooth_sdp_dip_record> for BtSdpDipRecord {
fn from(item: bindings::_bluetooth_sdp_dip_record) -> Self {
BtSdpDipRecord {
hdr: BtSdpHeaderOverlay::from(item.hdr),
spec_id: item.spec_id,
vendor: item.vendor,
vendor_id_source: item.vendor_id_source,
product: item.product,
version: item.version,
primary_record: item.primary_record,
}
}
}
#[derive(Clone, Debug)]
pub enum BtSdpRecord {
HeaderOverlay(BtSdpHeaderOverlay),
MapMas(BtSdpMasRecord),
MapMns(BtSdpMnsRecord),
PbapPse(BtSdpPseRecord),
PbapPce(BtSdpPceRecord),
OppServer(BtSdpOpsRecord),
SapServer(BtSdpSapRecord),
Dip(BtSdpDipRecord),
}
impl From<bindings::bluetooth_sdp_record> for BtSdpRecord {
fn from(item: bindings::bluetooth_sdp_record) -> Self {
let sdp_type = unsafe { BtSdpType::from(item.hdr.type_) };
match sdp_type {
BtSdpType::Raw => unsafe {
BtSdpRecord::HeaderOverlay(BtSdpHeaderOverlay::from(item.hdr))
},
BtSdpType::MapMas => unsafe { BtSdpRecord::MapMas(BtSdpMasRecord::from(item.mas)) },
BtSdpType::MapMns => unsafe { BtSdpRecord::MapMns(BtSdpMnsRecord::from(item.mns)) },
BtSdpType::PbapPse => unsafe { BtSdpRecord::PbapPse(BtSdpPseRecord::from(item.pse)) },
BtSdpType::PbapPce => unsafe { BtSdpRecord::PbapPce(BtSdpPceRecord::from(item.pce)) },
BtSdpType::OppServer => unsafe {
BtSdpRecord::OppServer(BtSdpOpsRecord::from(item.ops))
},
BtSdpType::SapServer => unsafe {
BtSdpRecord::SapServer(BtSdpSapRecord::from(item.sap))
},
BtSdpType::Dip => unsafe { BtSdpRecord::Dip(BtSdpDipRecord::from(item.dip)) },
}
}
}
impl BtSdpRecord {
fn convert_header<'a>(hdr: &'a mut BtSdpHeaderOverlay) -> bindings::bluetooth_sdp_hdr_overlay {
bindings::bluetooth_sdp_hdr_overlay {
type_: hdr.hdr.sdp_type.to_u32().unwrap(),
uuid: hdr.hdr.uuid,
service_name_length: hdr.hdr.service_name_length,
service_name: hdr.hdr.service_name.as_mut_ptr() as *mut c_char,
rfcomm_channel_number: hdr.hdr.rfcomm_channel_number,
l2cap_psm: hdr.hdr.l2cap_psm,
profile_version: hdr.hdr.profile_version,
user1_ptr_len: hdr.user1_len,
user1_ptr: hdr.user1_data.as_mut_ptr(),
user2_ptr_len: hdr.user2_len,
user2_ptr: hdr.user2_data.as_mut_ptr(),
}
}
// Get sdp record with lifetime tied to self
fn get_unsafe_record<'a>(&'a mut self) -> bindings::bluetooth_sdp_record {
match self {
BtSdpRecord::HeaderOverlay(ref mut hdr) => {
bindings::bluetooth_sdp_record { hdr: BtSdpRecord::convert_header(hdr) }
}
BtSdpRecord::MapMas(mas) => bindings::bluetooth_sdp_record {
mas: bindings::_bluetooth_sdp_mas_record {
hdr: BtSdpRecord::convert_header(&mut mas.hdr),
mas_instance_id: mas.mas_instance_id,
supported_features: mas.supported_features,
supported_message_types: mas.supported_message_types,
},
},
BtSdpRecord::MapMns(mns) => bindings::bluetooth_sdp_record {
mns: bindings::_bluetooth_sdp_mns_record {
hdr: BtSdpRecord::convert_header(&mut mns.hdr),
supported_features: mns.supported_features,
},
},
BtSdpRecord::PbapPse(pse) => bindings::bluetooth_sdp_record {
pse: bindings::_bluetooth_sdp_pse_record {
hdr: BtSdpRecord::convert_header(&mut pse.hdr),
supported_features: pse.supported_features,
supported_repositories: pse.supported_repositories,
},
},
BtSdpRecord::PbapPce(pce) => bindings::bluetooth_sdp_record {
pce: bindings::_bluetooth_sdp_pce_record {
hdr: BtSdpRecord::convert_header(&mut pce.hdr),
},
},
BtSdpRecord::OppServer(ops) => bindings::bluetooth_sdp_record {
ops: bindings::_bluetooth_sdp_ops_record {
hdr: BtSdpRecord::convert_header(&mut ops.hdr),
supported_formats_list_len: ops.supported_formats_list_len,
supported_formats_list: ops.supported_formats_list,
},
},
BtSdpRecord::SapServer(sap) => bindings::bluetooth_sdp_record {
sap: bindings::_bluetooth_sdp_sap_record {
hdr: BtSdpRecord::convert_header(&mut sap.hdr),
},
},
BtSdpRecord::Dip(dip) => bindings::bluetooth_sdp_record {
dip: bindings::_bluetooth_sdp_dip_record {
hdr: BtSdpRecord::convert_header(&mut dip.hdr),
spec_id: dip.spec_id,
vendor: dip.vendor,
vendor_id_source: dip.vendor_id_source,
product: dip.product,
version: dip.version,
primary_record: dip.primary_record,
},
},
}
}
}
#[derive(Debug)]
pub enum SdpCallbacks {
SdpSearch(BtStatus, RawAddress, Uuid, i32, Vec<BtSdpRecord>),
}
pub struct SdpCallbacksDispatcher {
pub dispatch: Box<dyn Fn(SdpCallbacks) + Send>,
}
type SdpCb = Arc<Mutex<SdpCallbacksDispatcher>>;
cb_variant!(SdpCb, sdp_search_cb -> SdpCallbacks::SdpSearch,
bindings::bt_status_t -> BtStatus,
*const FfiAddress, *const Uuid, i32,
*mut bindings::bluetooth_sdp_record, {
let _1 = unsafe { deref_const_ffi_address!(_1) };
let _2 = unsafe { *_2 };
let _4 = ptr_to_vec(_4, _3 as usize);
});
struct RawSdpWrapper {
pub raw: *const bindings::btsdp_interface_t,
}
unsafe impl Send for RawSdpWrapper {}
pub struct Sdp {
internal: RawSdpWrapper,
is_init: bool,
callbacks: Option<Box<bindings::btsdp_callbacks_t>>,
}
impl Sdp {
pub fn new(intf: &BluetoothInterface) -> Sdp {
let r = intf.get_profile_interface(SupportedProfiles::Sdp);
Sdp {
internal: RawSdpWrapper { raw: r as *const bindings::btsdp_interface_t },
is_init: false,
callbacks: None,
}
}
pub fn is_initialized(&self) -> bool {
self.is_init
}
pub fn initialize(&mut self, callbacks: SdpCallbacksDispatcher) -> bool {
if get_dispatchers().lock().unwrap().set::<SdpCb>(Arc::new(Mutex::new(callbacks))) {
panic!("Tried to set dispatcher for SdpCallbacks but it already existed");
}
let mut callbacks = Box::new(bindings::btsdp_callbacks_t {
size: 2 * 8,
sdp_search_cb: Some(sdp_search_cb),
});
let rawcb = &mut *callbacks;
let init = ccall!(self, init, rawcb);
self.is_init = BtStatus::from(init) == BtStatus::Success;
self.callbacks = Some(callbacks);
return self.is_init;
}
pub fn sdp_search(&self, address: &mut RawAddress, uuid: &Uuid) -> BtStatus {
let ffi_addr = cast_to_ffi_address!(address as *mut RawAddress);
BtStatus::from(ccall!(self, sdp_search, ffi_addr, uuid))
}
pub fn create_sdp_record(&self, record: &mut BtSdpRecord, handle: &mut i32) -> BtStatus {
let mut converted = record.get_unsafe_record();
let ptr = (&mut converted) as *mut bindings::bluetooth_sdp_record;
BtStatus::from(ccall!(self, create_sdp_record, ptr, handle))
}
pub fn remove_sdp_record(&self, handle: i32) -> BtStatus {
BtStatus::from(ccall!(self, remove_sdp_record, handle))
}
}