blob: 694575e5ad33d080942010d71339e6f9420f724b [file] [log] [blame]
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Netsim cxx libraries.
#![allow(dead_code)]
mod bluetooth;
pub mod captures;
mod config;
mod devices;
mod events;
mod http_server;
mod ranging;
mod resource;
mod service;
mod transport;
mod uwb;
mod version;
mod wifi;
// This feature is enabled only for CMake builds
#[cfg(feature = "local_ssl")]
mod openssl;
use std::pin::Pin;
use bluetooth::chip::{
create_add_rust_device_result, AddRustDeviceResult, RustBluetoothChipCallbacks,
};
use cxx::let_cxx_string;
use ffi::CxxServerResponseWriter;
use http_server::http_request::StrHeaders;
use http_server::server_response::ServerResponseWritable;
use crate::transport::dispatcher::handle_response;
use crate::transport::grpc::{register_grpc_transport, unregister_grpc_transport};
use crate::captures::handlers::{
handle_capture_cxx, handle_packet_request, handle_packet_response,
};
use crate::config::{get_dev, set_dev};
use crate::devices::devices_handler::{
add_chip_cxx, get_distance_cxx, handle_device_cxx, is_shutdown_time_cxx, remove_chip_cxx,
AddChipResultCxx,
};
use crate::ranging::*;
use crate::service::{create_service, Service};
use crate::uwb::facade::*;
use crate::version::*;
use netsim_common::system::netsimd_temp_dir_string;
#[allow(unsafe_op_in_unsafe_fn)]
#[cxx::bridge(namespace = "netsim")]
mod ffi {
extern "Rust" {
// Config
#[cxx_name = "GetDev"]
#[namespace = "netsim::config"]
fn get_dev() -> bool;
#[cxx_name = "SetDev"]
#[namespace = "netsim::config"]
fn set_dev(flag: bool);
// Ranging
#[cxx_name = "DistanceToRssi"]
fn distance_to_rssi(tx_power: i8, distance: f32) -> i8;
// Version
#[cxx_name = "GetVersion"]
fn get_version() -> String;
// Service
type Service;
#[cxx_name = "CreateService"]
fn create_service(
fd_startup_str: String,
no_cli_ui: bool,
no_web_ui: bool,
hci_port: u16,
instance_num: u16,
dev: bool,
) -> Box<Service>;
#[cxx_name = "SetUp"]
fn set_up(self: &Service);
#[cxx_name = "Run"]
fn run(self: &Service);
// System
#[cxx_name = "NetsimdTempDirString"]
fn netsimd_temp_dir_string() -> String;
// handlers for gRPC server's invocation of API calls
#[cxx_name = "HandleCaptureCxx"]
fn handle_capture_cxx(
responder: Pin<&mut CxxServerResponseWriter>,
method: String,
param: String,
body: String,
);
#[cxx_name = "HandleDeviceCxx"]
fn handle_device_cxx(
responder: Pin<&mut CxxServerResponseWriter>,
method: String,
param: String,
body: String,
);
// Transport.
#[cxx_name = HandleResponse]
#[namespace = "netsim::transport"]
fn handle_response(kind: u32, facade_id: u32, packet: &CxxVector<u8>, packet_type: u8);
#[cxx_name = RegisterGrpcTransport]
#[namespace = "netsim::transport"]
fn register_grpc_transport(kind: u32, facade_id: u32);
#[cxx_name = UnregisterGrpcTransport]
#[namespace = "netsim::transport"]
fn unregister_grpc_transport(kind: u32, facade_id: u32);
// Device Resource
type AddChipResultCxx;
#[cxx_name = "GetDeviceId"]
fn get_device_id(self: &AddChipResultCxx) -> u32;
#[cxx_name = "GetChipId"]
fn get_chip_id(self: &AddChipResultCxx) -> u32;
#[cxx_name = "GetFacadeId"]
fn get_facade_id(self: &AddChipResultCxx) -> u32;
#[cxx_name = "IsError"]
fn is_error(self: &AddChipResultCxx) -> bool;
#[cxx_name = AddChipCxx]
#[namespace = "netsim::device"]
fn add_chip_cxx(
device_guid: &str,
device_name: &str,
chip_kind: &CxxString,
chip_name: &str,
chip_manufacturer: &str,
chip_product_name: &str,
) -> Box<AddChipResultCxx>;
#[cxx_name = RemoveChipCxx]
#[namespace = "netsim::device"]
fn remove_chip_cxx(device_id: u32, chip_id: u32);
#[cxx_name = GetDistanceCxx]
#[namespace = "netsim::device"]
fn get_distance_cxx(a: u32, b: u32) -> f32;
#[cxx_name = IsShutdownTimeCxx]
#[namespace = "netsim::device"]
fn is_shutdown_time_cxx() -> bool;
// Capture Resource
#[cxx_name = HandleRequest]
#[namespace = "netsim::capture"]
fn handle_packet_request(
kind: u32,
facade_id: u32,
packet: &CxxVector<u8>,
packet_type: u32,
);
#[cxx_name = HandleResponse]
#[namespace = "netsim::capture"]
fn handle_packet_response(
kind: u32,
facade_id: u32,
packet: &CxxVector<u8>,
packet_type: u32,
);
// Rust Bluetooth device.
#[namespace = "netsim::hci::facade"]
type DynRustBluetoothChipCallbacks;
#[cxx_name = Tick]
#[namespace = "netsim::hci::facade"]
fn tick(dyn_callbacks: &mut DynRustBluetoothChipCallbacks);
#[cxx_name = ReceiveLinkLayerPacket]
#[namespace = "netsim::hci::facade"]
fn receive_link_layer_packet(
dyn_callbacks: &mut DynRustBluetoothChipCallbacks,
source_address: String,
destination_address: String,
packet_type: u8,
packet: &[u8],
);
// Bluetooth facade.
#[namespace = "netsim::hci::facade"]
type AddRustDeviceResult;
#[cxx_name = "CreateAddRustDeviceResult"]
#[namespace = "netsim::hci"]
fn create_add_rust_device_result(
facade_id: u32,
rust_chip: UniquePtr<RustBluetoothChip>,
) -> Box<AddRustDeviceResult>;
// Uwb Facade.
#[cxx_name = HandleUwbRequestCxx]
#[namespace = "netsim::uwb"]
fn handle_uwb_request(facade_id: u32, packet: &[u8]);
#[cxx_name = PatchCxx]
#[namespace = "netsim::uwb::facade"]
pub fn uwb_patch(_facade_id: u32, _proto_bytes: &[u8]);
#[cxx_name = GetCxx]
#[namespace = "netsim::uwb::facade"]
pub fn uwb_get(_facade_id: u32) -> Vec<u8>;
#[cxx_name = Reset]
#[namespace = "netsim::uwb::facade"]
pub fn uwb_reset(_facade_id: u32);
#[cxx_name = Remove]
#[namespace = "netsim::uwb::facade"]
pub fn uwb_remove(_facade_id: u32);
#[cxx_name = Add]
#[namespace = "netsim::uwb::facade"]
pub fn uwb_add(_chip_id: u32) -> u32;
#[cxx_name = Start]
#[namespace = "netsim::uwb::facade"]
pub fn uwb_start();
#[cxx_name = Stop]
#[namespace = "netsim::uwb::facade"]
pub fn uwb_stop();
}
unsafe extern "C++" {
/// A C++ class which can be used to respond to a request.
include!("frontend/server_response_writable.h");
#[namespace = "netsim::frontend"]
type CxxServerResponseWriter;
#[namespace = "netsim::frontend"]
fn put_ok_with_length(self: &CxxServerResponseWriter, mime_type: &CxxString, length: usize);
#[namespace = "netsim::frontend"]
fn put_chunk(self: &CxxServerResponseWriter, chunk: &[u8]);
#[namespace = "netsim::frontend"]
fn put_ok(self: &CxxServerResponseWriter, mime_type: &CxxString, body: &CxxString);
#[namespace = "netsim::frontend"]
fn put_error(self: &CxxServerResponseWriter, error_code: u32, error_message: &CxxString);
include!("packet_hub/packet_hub.h");
#[rust_name = "handle_request_cxx"]
#[namespace = "netsim::packet_hub"]
fn HandleRequestCxx(kind: u32, facade_id: u32, packet: &Vec<u8>, packet_type: u8);
// Grpc server.
include!("backend/backend_packet_hub.h");
#[rust_name = handle_grpc_response]
#[namespace = "netsim::backend"]
fn HandleResponseCxx(kind: u32, facade_id: u32, packet: &CxxVector<u8>, packet_type: u8);
// Bluetooth facade.
include!("hci/hci_packet_hub.h");
#[rust_name = handle_bt_request]
#[namespace = "netsim::hci"]
fn HandleBtRequestCxx(facade_id: u32, packet_type: u8, packet: &Vec<u8>);
// Rust Bluetooth device.
include!("hci/rust_device.h");
#[namespace = "netsim::hci::facade"]
type RustBluetoothChip;
#[rust_name = send_link_layer_packet]
#[namespace = "netsim::hci::facade"]
fn SendLinkLayerPacket(
self: &RustBluetoothChip,
packet: &[u8],
packet_type: u8,
tx_power: i8,
);
#[rust_name = generate_advertising_packet]
#[namespace = "netsim::hci::facade"]
fn GenerateAdvertisingPacket(address: &String, packet: &[u8]) -> Vec<u8>;
#[rust_name = generate_scan_response_packet]
#[namespace = "netsim::hci::facade"]
fn GenerateScanResponsePacket(
source_address: &String,
destination_address: &String,
packet: &[u8],
) -> Vec<u8>;
include!("hci/bluetooth_facade.h");
#[rust_name = bluetooth_patch_cxx]
#[namespace = "netsim::hci::facade"]
pub fn PatchCxx(facade_id: u32, proto_bytes: &[u8]);
#[rust_name = bluetooth_get_cxx]
#[namespace = "netsim::hci::facade"]
pub fn GetCxx(facade_id: u32) -> Vec<u8>;
#[rust_name = bluetooth_reset]
#[namespace = "netsim::hci::facade"]
pub fn Reset(facade_id: u32);
#[rust_name = bluetooth_remove]
#[namespace = "netsim::hci::facade"]
pub fn Remove(facade_id: u32);
#[rust_name = bluetooth_add]
#[namespace = "netsim::hci::facade"]
pub fn Add(_chip_id: u32) -> u32;
/*
From https://cxx.rs/binding/box.html#restrictions,
```
If T is an opaque Rust type, the Rust type is required to be Sized i.e. size known at compile time. In the future we may introduce support for dynamically sized opaque Rust types.
```
The workaround is using Box<dyn MyData> (fat pointer) as the opaque type.
Reference:
- Passing trait objects to C++. https://github.com/dtolnay/cxx/issues/665.
- Exposing trait methods to C++. https://github.com/dtolnay/cxx/issues/667
*/
#[rust_name = bluetooth_add_rust_device]
#[namespace = "netsim::hci::facade"]
pub fn AddRustDevice(
device_id: u32,
callbacks: Box<DynRustBluetoothChipCallbacks>,
string_type: &CxxString,
address: &CxxString,
) -> Box<AddRustDeviceResult>;
#[rust_name = bluetooth_start]
#[namespace = "netsim::hci::facade"]
pub fn Start(instance_num: u16);
#[rust_name = bluetooth_stop]
#[namespace = "netsim::hci::facade"]
pub fn Stop();
// WiFi facade.
include!("wifi/wifi_packet_hub.h");
#[rust_name = handle_wifi_request]
#[namespace = "netsim::wifi"]
fn HandleWifiRequestCxx(facade_id: u32, packet: &Vec<u8>);
include!("wifi/wifi_facade.h");
#[rust_name = wifi_patch_cxx]
#[namespace = "netsim::wifi::facade"]
pub fn PatchCxx(facade_id: u32, proto_bytes: &[u8]);
#[rust_name = wifi_get_cxx]
#[namespace = "netsim::wifi::facade"]
pub fn GetCxx(facade_id: u32) -> Vec<u8>;
#[rust_name = wifi_reset]
#[namespace = "netsim::wifi::facade"]
pub fn Reset(facade_id: u32);
#[rust_name = wifi_remove]
#[namespace = "netsim::wifi::facade"]
pub fn Remove(facade_id: u32);
#[rust_name = wifi_add]
#[namespace = "netsim::wifi::facade"]
pub fn Add(_chip_id: u32) -> u32;
#[rust_name = wifi_start]
#[namespace = "netsim::wifi::facade"]
pub fn Start();
#[rust_name = wifi_stop]
#[namespace = "netsim::wifi::facade"]
pub fn Stop();
}
}
// It's required so `RustBluetoothChip` can be sent between threads safely.
// Ref: How to use opaque types in threads? https://github.com/dtolnay/cxx/issues/1175
// SAFETY: Nothing in `RustBluetoothChip` depends on being run on a particular thread.
unsafe impl Send for ffi::RustBluetoothChip {}
type DynRustBluetoothChipCallbacks = Box<dyn RustBluetoothChipCallbacks>;
fn tick(dyn_callbacks: &mut DynRustBluetoothChipCallbacks) {
(**dyn_callbacks).tick();
}
fn receive_link_layer_packet(
dyn_callbacks: &mut DynRustBluetoothChipCallbacks,
source_address: String,
destination_address: String,
packet_type: u8,
packet: &[u8],
) {
(**dyn_callbacks).receive_link_layer_packet(
source_address,
destination_address,
packet_type,
packet,
);
}
/// CxxServerResponseWriter is defined in server_response_writable.h
/// Wrapper struct allows the impl to discover the respective C++ methods
struct CxxServerResponseWriterWrapper<'a> {
writer: Pin<&'a mut CxxServerResponseWriter>,
}
impl ServerResponseWritable for CxxServerResponseWriterWrapper<'_> {
fn put_ok_with_length(&mut self, mime_type: &str, length: usize, _headers: StrHeaders) {
let_cxx_string!(mime_type = mime_type);
self.writer.put_ok_with_length(&mime_type, length);
}
fn put_chunk(&mut self, chunk: &[u8]) {
self.writer.put_chunk(chunk);
}
fn put_ok(&mut self, mime_type: &str, body: &str, _headers: StrHeaders) {
let_cxx_string!(mime_type = mime_type);
let_cxx_string!(body = body);
self.writer.put_ok(&mime_type, &body);
}
fn put_error(&mut self, error_code: u16, error_message: &str) {
let_cxx_string!(error_message = error_message);
self.writer.put_error(error_code.into(), &error_message);
}
fn put_ok_with_vec(&mut self, _mime_type: &str, _body: Vec<u8>, _headers: StrHeaders) {
todo!()
}
fn put_ok_switch_protocol(&mut self, _connection: &str, _headers: StrHeaders) {
todo!()
}
}