xref: /aosp_15_r20/tools/netsim/rust/daemon/src/ffi.rs (revision cf78ab8cffb8fc9207af348f23af247fb04370a6)
1 // Copyright 2023 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! Netsim daemon cxx libraries.
16 
17 use std::pin::Pin;
18 
19 use crate::bluetooth::chip::{
20     create_add_rust_device_result, AddRustDeviceResult, RustBluetoothChipCallbacks,
21 };
22 use crate::http_server::server_response::ServerResponseWritable;
23 use crate::http_server::server_response::StrHeaders;
24 use cxx::let_cxx_string;
25 
26 use crate::captures::captures_handler::handle_capture_cxx;
27 use crate::devices::devices_handler::{
28     add_chip_cxx, get_distance_cxx, handle_device_cxx, remove_chip_cxx, AddChipResultCxx,
29 };
30 use crate::ranging::*;
31 use crate::version::*;
32 use crate::wireless::{
33     bluetooth::report_invalid_packet_cxx, handle_request_cxx, handle_response_cxx,
34 };
35 
36 #[allow(unsafe_op_in_unsafe_fn)]
37 #[cxx::bridge(namespace = "netsim::wireless")]
38 pub mod ffi_wireless {
39     extern "Rust" {
40         #[cxx_name = HandleRequestCxx]
handle_request_cxx(chip_id: u32, packet: &CxxVector<u8>, packet_type: u8)41         fn handle_request_cxx(chip_id: u32, packet: &CxxVector<u8>, packet_type: u8);
42 
43         #[cxx_name = HandleResponse]
handle_response_cxx(chip_id: u32, packet: &CxxVector<u8>, packet_type: u8)44         fn handle_response_cxx(chip_id: u32, packet: &CxxVector<u8>, packet_type: u8);
45     }
46 }
47 
48 #[allow(unsafe_op_in_unsafe_fn)]
49 #[cxx::bridge(namespace = "netsim::transport")]
50 pub mod ffi_transport {
51     unsafe extern "C++" {
52         // Grpc client.
53         // Expose functions in Cuttlefish only, because it's only used by CVDs and it's
54         // unable to pass function pointers on Windows.
55         #[cfg(feature = "cuttlefish")]
56         include!("backend/grpc_client.h");
57 
58         #[allow(dead_code)]
59         #[rust_name = stream_packets]
60         #[namespace = "netsim::backend::client"]
61         #[cfg(feature = "cuttlefish")]
StreamPackets(server: &String) -> u3262         fn StreamPackets(server: &String) -> u32;
63 
64         #[allow(dead_code)]
65         #[rust_name = read_packet_response_loop]
66         #[namespace = "netsim::backend::client"]
67         #[cfg(feature = "cuttlefish")]
ReadPacketResponseLoop( stream_id: u32, read_fn: fn(stream_id: u32, proto_bytes: &[u8]), ) -> bool68         fn ReadPacketResponseLoop(
69             stream_id: u32,
70             read_fn: fn(stream_id: u32, proto_bytes: &[u8]),
71         ) -> bool;
72 
73         #[allow(dead_code)]
74         #[rust_name = write_packet_request]
75         #[cfg(feature = "cuttlefish")]
76         #[namespace = "netsim::backend::client"]
WritePacketRequest(stream_id: u32, proto_bytes: &[u8]) -> bool77         fn WritePacketRequest(stream_id: u32, proto_bytes: &[u8]) -> bool;
78 
79     }
80 }
81 
82 #[allow(clippy::needless_maybe_sized)]
83 #[allow(unsafe_op_in_unsafe_fn)]
84 #[cxx::bridge(namespace = "netsim")]
85 pub mod ffi_bluetooth {
86     extern "Rust" {
87         // Rust Bluetooth device.
88         #[namespace = "netsim::hci::facade"]
89         type DynRustBluetoothChipCallbacks;
90 
91         #[cxx_name = Tick]
92         #[namespace = "netsim::hci::facade"]
tick(dyn_callbacks: &mut DynRustBluetoothChipCallbacks)93         fn tick(dyn_callbacks: &mut DynRustBluetoothChipCallbacks);
94 
95         #[cxx_name = ReceiveLinkLayerPacket]
96         #[namespace = "netsim::hci::facade"]
receive_link_layer_packet( dyn_callbacks: &mut DynRustBluetoothChipCallbacks, source_address: String, destination_address: String, packet_type: u8, packet: &[u8], )97         fn receive_link_layer_packet(
98             dyn_callbacks: &mut DynRustBluetoothChipCallbacks,
99             source_address: String,
100             destination_address: String,
101             packet_type: u8,
102             packet: &[u8],
103         );
104 
105         // Bluetooth facade.
106         #[namespace = "netsim::hci::facade"]
107         type AddRustDeviceResult;
108         #[cxx_name = "CreateAddRustDeviceResult"]
109         #[namespace = "netsim::hci"]
create_add_rust_device_result( facade_id: u32, rust_chip: UniquePtr<RustBluetoothChip>, ) -> Box<AddRustDeviceResult>110         fn create_add_rust_device_result(
111             facade_id: u32,
112             rust_chip: UniquePtr<RustBluetoothChip>,
113         ) -> Box<AddRustDeviceResult>;
114 
115         // Rust Invalid Packet Report
116         #[cxx_name = "ReportInvalidPacket"]
117         #[namespace = "netsim::hci::facade"]
report_invalid_packet_cxx( rootcanal_id: u32, reason: i32, description: &CxxString, packet: &CxxVector<u8>, )118         fn report_invalid_packet_cxx(
119             rootcanal_id: u32,
120             reason: i32,
121             description: &CxxString,
122             packet: &CxxVector<u8>,
123         );
124     }
125 
126     #[allow(dead_code)]
127     unsafe extern "C++" {
128         // Bluetooth facade.
129         include!("hci/hci_packet_hub.h");
130 
131         #[rust_name = handle_bt_request]
132         #[namespace = "netsim::hci"]
HandleBtRequestCxx(rootcanal_id: u32, packet_type: u8, packet: &Vec<u8>)133         fn HandleBtRequestCxx(rootcanal_id: u32, packet_type: u8, packet: &Vec<u8>);
134 
135         // Rust Bluetooth device.
136         include!("hci/rust_device.h");
137 
138         #[namespace = "netsim::hci::facade"]
139         type RustBluetoothChip;
140         #[rust_name = send_link_layer_le_packet]
141         #[namespace = "netsim::hci::facade"]
SendLinkLayerLePacket(self: &RustBluetoothChip, packet: &[u8], tx_power: i8)142         fn SendLinkLayerLePacket(self: &RustBluetoothChip, packet: &[u8], tx_power: i8);
143 
144         include!("hci/bluetooth_facade.h");
145 
146         #[rust_name = bluetooth_get_cxx]
147         #[namespace = "netsim::hci::facade"]
GetCxx(rootcanal_id: u32) -> Vec<u8>148         pub fn GetCxx(rootcanal_id: u32) -> Vec<u8>;
149 
150         #[rust_name = bluetooth_reset]
151         #[namespace = "netsim::hci::facade"]
Reset(rootcanal_id: u32)152         pub fn Reset(rootcanal_id: u32);
153 
154         #[rust_name = bluetooth_remove]
155         #[namespace = "netsim::hci::facade"]
Remove(rootcanal_id: u32)156         pub fn Remove(rootcanal_id: u32);
157 
158         #[rust_name = bluetooth_add]
159         #[namespace = "netsim::hci::facade"]
Add(chip_id: u32, address: &CxxString, controller_proto_bytes: &[u8]) -> u32160         pub fn Add(chip_id: u32, address: &CxxString, controller_proto_bytes: &[u8]) -> u32;
161 
162         /*
163         From https://cxx.rs/binding/box.html#restrictions,
164         ```
165         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.
166         ```
167 
168         The workaround is using Box<dyn MyData> (fat pointer) as the opaque type.
169         Reference:
170         - Passing trait objects to C++. https://github.com/dtolnay/cxx/issues/665.
171         - Exposing trait methods to C++. https://github.com/dtolnay/cxx/issues/667
172                 */
173         #[rust_name = bluetooth_add_rust_device]
174         #[namespace = "netsim::hci::facade"]
AddRustDevice( chip_id: u32, callbacks: Box<DynRustBluetoothChipCallbacks>, string_type: &CxxString, address: &CxxString, ) -> Box<AddRustDeviceResult>175         pub fn AddRustDevice(
176             chip_id: u32,
177             callbacks: Box<DynRustBluetoothChipCallbacks>,
178             string_type: &CxxString,
179             address: &CxxString,
180         ) -> Box<AddRustDeviceResult>;
181 
182         /// The provided address must be 6 bytes in length
183         #[rust_name = bluetooth_set_rust_device_address]
184         #[namespace = "netsim::hci::facade"]
SetRustDeviceAddress(rootcanal_id: u32, address: [u8; 6])185         pub fn SetRustDeviceAddress(rootcanal_id: u32, address: [u8; 6]);
186 
187         #[rust_name = bluetooth_remove_rust_device]
188         #[namespace = "netsim::hci::facade"]
RemoveRustDevice(rootcanal_id: u32)189         pub fn RemoveRustDevice(rootcanal_id: u32);
190 
191         #[rust_name = bluetooth_start]
192         #[namespace = "netsim::hci::facade"]
Start(proto_bytes: &[u8], instance_num: u16)193         pub fn Start(proto_bytes: &[u8], instance_num: u16);
194 
195         #[rust_name = bluetooth_stop]
196         #[namespace = "netsim::hci::facade"]
Stop()197         pub fn Stop();
198 
199         #[rust_name = add_device_to_phy]
200         #[namespace = "netsim::hci::facade"]
AddDeviceToPhy(rootcanal_id: u32, is_low_energy: bool)201         pub fn AddDeviceToPhy(rootcanal_id: u32, is_low_energy: bool);
202 
203         #[rust_name = remove_device_from_phy]
204         #[namespace = "netsim::hci::facade"]
RemoveDeviceFromPhy(rootcanal_id: u32, is_low_energy: bool)205         pub fn RemoveDeviceFromPhy(rootcanal_id: u32, is_low_energy: bool);
206     }
207 }
208 
209 #[allow(clippy::needless_maybe_sized)]
210 #[allow(unsafe_op_in_unsafe_fn)]
211 #[cxx::bridge(namespace = "netsim::device")]
212 pub mod ffi_devices {
213     extern "Rust" {
214 
215         // Device Resource
216         type AddChipResultCxx;
217         #[cxx_name = "GetDeviceId"]
get_device_id(self: &AddChipResultCxx) -> u32218         fn get_device_id(self: &AddChipResultCxx) -> u32;
219         #[cxx_name = "GetChipId"]
get_chip_id(self: &AddChipResultCxx) -> u32220         fn get_chip_id(self: &AddChipResultCxx) -> u32;
221         #[cxx_name = "IsError"]
is_error(self: &AddChipResultCxx) -> bool222         fn is_error(self: &AddChipResultCxx) -> bool;
223 
224         #[allow(clippy::too_many_arguments)]
225         #[cxx_name = AddChipCxx]
add_chip_cxx( device_guid: &str, device_name: &str, chip_kind: &CxxString, chip_address: &str, chip_name: &str, chip_manufacturer: &str, chip_product_name: &str, bt_properties: &CxxVector<u8>, kind: &str, version: &str, sdk_version: &str, build_id: &str, variant: &str, arch: &str, ) -> Box<AddChipResultCxx>226         fn add_chip_cxx(
227             device_guid: &str,
228             device_name: &str,
229             chip_kind: &CxxString,
230             chip_address: &str,
231             chip_name: &str,
232             chip_manufacturer: &str,
233             chip_product_name: &str,
234             bt_properties: &CxxVector<u8>,
235             kind: &str,
236             version: &str,
237             sdk_version: &str,
238             build_id: &str,
239             variant: &str,
240             arch: &str,
241         ) -> Box<AddChipResultCxx>;
242 
243         #[cxx_name = RemoveChipCxx]
remove_chip_cxx(device_id: u32, chip_id: u32)244         fn remove_chip_cxx(device_id: u32, chip_id: u32);
245 
246         #[cxx_name = GetDistanceCxx]
get_distance_cxx(a: u32, b: u32) -> f32247         fn get_distance_cxx(a: u32, b: u32) -> f32;
248     }
249 }
250 
251 #[allow(unsafe_op_in_unsafe_fn)]
252 #[cxx::bridge(namespace = "netsim")]
253 pub mod ffi_response_writable {
254     extern "Rust" {
255         // handlers for gRPC server's invocation of API calls
256 
257         #[cxx_name = "HandleCaptureCxx"]
handle_capture_cxx( responder: Pin<&mut CxxServerResponseWriter>, method: String, param: String, body: String, )258         fn handle_capture_cxx(
259             responder: Pin<&mut CxxServerResponseWriter>,
260             method: String,
261             param: String,
262             body: String,
263         );
264 
265         #[cxx_name = "HandleDeviceCxx"]
handle_device_cxx( responder: Pin<&mut CxxServerResponseWriter>, method: String, param: String, body: String, )266         fn handle_device_cxx(
267             responder: Pin<&mut CxxServerResponseWriter>,
268             method: String,
269             param: String,
270             body: String,
271         );
272     }
273     unsafe extern "C++" {
274         /// A C++ class which can be used to respond to a request.
275         include!("frontend/server_response_writable.h");
276 
277         #[namespace = "netsim::frontend"]
278         type CxxServerResponseWriter;
279 
280         #[namespace = "netsim::frontend"]
put_ok_with_length(self: &CxxServerResponseWriter, mime_type: &CxxString, length: usize)281         fn put_ok_with_length(self: &CxxServerResponseWriter, mime_type: &CxxString, length: usize);
282 
283         #[namespace = "netsim::frontend"]
put_chunk(self: &CxxServerResponseWriter, chunk: &[u8])284         fn put_chunk(self: &CxxServerResponseWriter, chunk: &[u8]);
285 
286         #[namespace = "netsim::frontend"]
put_ok(self: &CxxServerResponseWriter, mime_type: &CxxString, body: &CxxString)287         fn put_ok(self: &CxxServerResponseWriter, mime_type: &CxxString, body: &CxxString);
288 
289         #[namespace = "netsim::frontend"]
put_error(self: &CxxServerResponseWriter, error_code: u32, error_message: &CxxString)290         fn put_error(self: &CxxServerResponseWriter, error_code: u32, error_message: &CxxString);
291 
292     }
293 }
294 
295 #[allow(unsafe_op_in_unsafe_fn)]
296 #[cxx::bridge(namespace = "netsim")]
297 pub mod ffi_util {
298     extern "Rust" {
299         // Ranging
300 
301         #[cxx_name = "DistanceToRssi"]
distance_to_rssi(tx_power: i8, distance: f32) -> i8302         fn distance_to_rssi(tx_power: i8, distance: f32) -> i8;
303 
304         // Version
305 
306         #[cxx_name = "GetVersion"]
get_version() -> String307         fn get_version() -> String;
308     }
309 
310     #[allow(dead_code)]
311     unsafe extern "C++" {
312 
313         // Crash report.
314         include!("util/crash_report.h");
315 
316         #[rust_name = set_up_crash_report]
317         #[namespace = "netsim"]
SetUpCrashReport()318         pub fn SetUpCrashReport();
319     }
320 }
321 
322 // It's required so `RustBluetoothChip` can be sent between threads safely.
323 // Ref: How to use opaque types in threads? https://github.com/dtolnay/cxx/issues/1175
324 // SAFETY: Nothing in `RustBluetoothChip` depends on being run on a particular thread.
325 unsafe impl Send for ffi_bluetooth::RustBluetoothChip {}
326 
327 type DynRustBluetoothChipCallbacks = Box<dyn RustBluetoothChipCallbacks>;
328 
tick(dyn_callbacks: &mut DynRustBluetoothChipCallbacks)329 fn tick(dyn_callbacks: &mut DynRustBluetoothChipCallbacks) {
330     (**dyn_callbacks).tick();
331 }
332 
receive_link_layer_packet( dyn_callbacks: &mut DynRustBluetoothChipCallbacks, source_address: String, destination_address: String, packet_type: u8, packet: &[u8], )333 fn receive_link_layer_packet(
334     dyn_callbacks: &mut DynRustBluetoothChipCallbacks,
335     source_address: String,
336     destination_address: String,
337     packet_type: u8,
338     packet: &[u8],
339 ) {
340     (**dyn_callbacks).receive_link_layer_packet(
341         source_address,
342         destination_address,
343         packet_type,
344         packet,
345     );
346 }
347 
348 /// CxxServerResponseWriter is defined in server_response_writable.h
349 /// Wrapper struct allows the impl to discover the respective C++ methods
350 pub struct CxxServerResponseWriterWrapper<'a> {
351     pub writer: Pin<&'a mut ffi_response_writable::CxxServerResponseWriter>,
352 }
353 
354 impl ServerResponseWritable for CxxServerResponseWriterWrapper<'_> {
put_ok_with_length(&mut self, mime_type: &str, length: usize, _headers: StrHeaders)355     fn put_ok_with_length(&mut self, mime_type: &str, length: usize, _headers: StrHeaders) {
356         let_cxx_string!(mime_type = mime_type);
357         self.writer.put_ok_with_length(&mime_type, length);
358     }
put_chunk(&mut self, chunk: &[u8])359     fn put_chunk(&mut self, chunk: &[u8]) {
360         self.writer.put_chunk(chunk);
361     }
put_ok(&mut self, mime_type: &str, body: &str, _headers: StrHeaders)362     fn put_ok(&mut self, mime_type: &str, body: &str, _headers: StrHeaders) {
363         let_cxx_string!(mime_type = mime_type);
364         let_cxx_string!(body = body);
365         self.writer.put_ok(&mime_type, &body);
366     }
put_error(&mut self, error_code: u16, error_message: &str)367     fn put_error(&mut self, error_code: u16, error_message: &str) {
368         let_cxx_string!(error_message = error_message);
369         self.writer.put_error(error_code.into(), &error_message);
370     }
371 
put_ok_with_vec(&mut self, _mime_type: &str, _body: Vec<u8>, _headers: StrHeaders)372     fn put_ok_with_vec(&mut self, _mime_type: &str, _body: Vec<u8>, _headers: StrHeaders) {
373         todo!()
374     }
put_ok_switch_protocol(&mut self, _connection: &str, _headers: StrHeaders)375     fn put_ok_switch_protocol(&mut self, _connection: &str, _headers: StrHeaders) {
376         todo!()
377     }
378 }
379