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