• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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::transport::grpc::{register_grpc_transport, unregister_grpc_transport};
32 use crate::version::*;
33 use crate::wireless::wifi::handle_wifi_response;
34 use crate::wireless::{
35     bluetooth::report_invalid_packet_cxx, handle_request_cxx, handle_response_cxx,
36 };
37 
38 #[allow(unsafe_op_in_unsafe_fn)]
39 #[cxx::bridge(namespace = "netsim::wireless")]
40 pub mod ffi_wireless {
41     extern "Rust" {
42         #[cxx_name = HandleRequestCxx]
handle_request_cxx(chip_id: u32, packet: &CxxVector<u8>, packet_type: u8)43         fn handle_request_cxx(chip_id: u32, packet: &CxxVector<u8>, packet_type: u8);
44 
45         #[cxx_name = HandleResponse]
handle_response_cxx(chip_id: u32, packet: &CxxVector<u8>, packet_type: u8)46         fn handle_response_cxx(chip_id: u32, packet: &CxxVector<u8>, packet_type: u8);
47     }
48 }
49 
50 #[allow(unsafe_op_in_unsafe_fn)]
51 #[cxx::bridge(namespace = "netsim::transport")]
52 pub mod ffi_transport {
53     extern "Rust" {
54         #[cxx_name = RegisterGrpcTransport]
register_grpc_transport(chip_id: u32)55         fn register_grpc_transport(chip_id: u32);
56 
57         #[cxx_name = UnregisterGrpcTransport]
unregister_grpc_transport(chip_id: u32)58         fn unregister_grpc_transport(chip_id: u32);
59     }
60 
61     unsafe extern "C++" {
62         // Grpc server.
63         include!("backend/backend_packet_hub.h");
64 
65         #[rust_name = handle_grpc_response]
66         #[namespace = "netsim::backend"]
HandleResponseCxx(chip_id: u32, packet: &Vec<u8>, packet_type: u8)67         fn HandleResponseCxx(chip_id: u32, packet: &Vec<u8>, packet_type: u8);
68 
69         include!("core/server.h");
70 
71         #[namespace = "netsim::server"]
72         type GrpcServer;
73         #[rust_name = shut_down]
74         #[namespace = "netsim::server"]
Shutdown(self: &GrpcServer)75         fn Shutdown(self: &GrpcServer);
76 
77         #[rust_name = get_grpc_port]
78         #[namespace = "netsim::server"]
GetGrpcPort(self: &GrpcServer) -> u3279         fn GetGrpcPort(self: &GrpcServer) -> u32;
80 
81         #[rust_name = run_grpc_server_cxx]
82         #[namespace = "netsim::server"]
RunGrpcServerCxx( netsim_grpc_port: u32, no_cli_ui: bool, vsock: u16, ) -> UniquePtr<GrpcServer>83         pub fn RunGrpcServerCxx(
84             netsim_grpc_port: u32,
85             no_cli_ui: bool,
86             vsock: u16,
87         ) -> UniquePtr<GrpcServer>;
88 
89         // Grpc client.
90         // Expose functions in Cuttlefish only, because it's only used by CVDs and it's
91         // unable to pass function pointers on Windows.
92         #[cfg(feature = "cuttlefish")]
93         include!("backend/grpc_client.h");
94 
95         #[allow(dead_code)]
96         #[rust_name = stream_packets]
97         #[namespace = "netsim::backend::client"]
98         #[cfg(feature = "cuttlefish")]
StreamPackets(server: &String) -> u3299         fn StreamPackets(server: &String) -> u32;
100 
101         #[allow(dead_code)]
102         #[rust_name = read_packet_response_loop]
103         #[namespace = "netsim::backend::client"]
104         #[cfg(feature = "cuttlefish")]
ReadPacketResponseLoop( stream_id: u32, read_fn: fn(stream_id: u32, proto_bytes: &[u8]), ) -> bool105         fn ReadPacketResponseLoop(
106             stream_id: u32,
107             read_fn: fn(stream_id: u32, proto_bytes: &[u8]),
108         ) -> bool;
109 
110         #[allow(dead_code)]
111         #[rust_name = write_packet_request]
112         #[cfg(feature = "cuttlefish")]
113         #[namespace = "netsim::backend::client"]
WritePacketRequest(stream_id: u32, proto_bytes: &[u8]) -> bool114         fn WritePacketRequest(stream_id: u32, proto_bytes: &[u8]) -> bool;
115 
116     }
117 }
118 
119 #[allow(unsafe_op_in_unsafe_fn)]
120 #[cxx::bridge(namespace = "netsim")]
121 pub mod ffi_bluetooth {
122     extern "Rust" {
123         // Rust Bluetooth device.
124         #[namespace = "netsim::hci::facade"]
125         type DynRustBluetoothChipCallbacks;
126 
127         #[cxx_name = Tick]
128         #[namespace = "netsim::hci::facade"]
tick(dyn_callbacks: &mut DynRustBluetoothChipCallbacks)129         fn tick(dyn_callbacks: &mut DynRustBluetoothChipCallbacks);
130 
131         #[cxx_name = ReceiveLinkLayerPacket]
132         #[namespace = "netsim::hci::facade"]
receive_link_layer_packet( dyn_callbacks: &mut DynRustBluetoothChipCallbacks, source_address: String, destination_address: String, packet_type: u8, packet: &[u8], )133         fn receive_link_layer_packet(
134             dyn_callbacks: &mut DynRustBluetoothChipCallbacks,
135             source_address: String,
136             destination_address: String,
137             packet_type: u8,
138             packet: &[u8],
139         );
140 
141         // Bluetooth facade.
142         #[namespace = "netsim::hci::facade"]
143         type AddRustDeviceResult;
144         #[cxx_name = "CreateAddRustDeviceResult"]
145         #[namespace = "netsim::hci"]
create_add_rust_device_result( facade_id: u32, rust_chip: UniquePtr<RustBluetoothChip>, ) -> Box<AddRustDeviceResult>146         fn create_add_rust_device_result(
147             facade_id: u32,
148             rust_chip: UniquePtr<RustBluetoothChip>,
149         ) -> Box<AddRustDeviceResult>;
150 
151         // Rust Invalid Packet Report
152         #[cxx_name = "ReportInvalidPacket"]
153         #[namespace = "netsim::hci::facade"]
report_invalid_packet_cxx( rootcanal_id: u32, reason: i32, description: &CxxString, packet: &CxxVector<u8>, )154         fn report_invalid_packet_cxx(
155             rootcanal_id: u32,
156             reason: i32,
157             description: &CxxString,
158             packet: &CxxVector<u8>,
159         );
160     }
161 
162     #[allow(dead_code)]
163     unsafe extern "C++" {
164         // Bluetooth facade.
165         include!("hci/hci_packet_hub.h");
166 
167         #[rust_name = handle_bt_request]
168         #[namespace = "netsim::hci"]
HandleBtRequestCxx(rootcanal_id: u32, packet_type: u8, packet: &Vec<u8>)169         fn HandleBtRequestCxx(rootcanal_id: u32, packet_type: u8, packet: &Vec<u8>);
170 
171         // Rust Bluetooth device.
172         include!("hci/rust_device.h");
173 
174         #[namespace = "netsim::hci::facade"]
175         type RustBluetoothChip;
176         #[rust_name = send_link_layer_le_packet]
177         #[namespace = "netsim::hci::facade"]
SendLinkLayerLePacket(self: &RustBluetoothChip, packet: &[u8], tx_power: i8)178         fn SendLinkLayerLePacket(self: &RustBluetoothChip, packet: &[u8], tx_power: i8);
179 
180         include!("hci/bluetooth_facade.h");
181 
182         #[rust_name = bluetooth_get_cxx]
183         #[namespace = "netsim::hci::facade"]
GetCxx(rootcanal_id: u32) -> Vec<u8>184         pub fn GetCxx(rootcanal_id: u32) -> Vec<u8>;
185 
186         #[rust_name = bluetooth_reset]
187         #[namespace = "netsim::hci::facade"]
Reset(rootcanal_id: u32)188         pub fn Reset(rootcanal_id: u32);
189 
190         #[rust_name = bluetooth_remove]
191         #[namespace = "netsim::hci::facade"]
Remove(rootcanal_id: u32)192         pub fn Remove(rootcanal_id: u32);
193 
194         #[rust_name = bluetooth_add]
195         #[namespace = "netsim::hci::facade"]
Add(chip_id: u32, address: &CxxString, controller_proto_bytes: &[u8]) -> u32196         pub fn Add(chip_id: u32, address: &CxxString, controller_proto_bytes: &[u8]) -> u32;
197 
198         /*
199         From https://cxx.rs/binding/box.html#restrictions,
200         ```
201         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.
202         ```
203 
204         The workaround is using Box<dyn MyData> (fat pointer) as the opaque type.
205         Reference:
206         - Passing trait objects to C++. https://github.com/dtolnay/cxx/issues/665.
207         - Exposing trait methods to C++. https://github.com/dtolnay/cxx/issues/667
208                 */
209         #[rust_name = bluetooth_add_rust_device]
210         #[namespace = "netsim::hci::facade"]
AddRustDevice( chip_id: u32, callbacks: Box<DynRustBluetoothChipCallbacks>, string_type: &CxxString, address: &CxxString, ) -> Box<AddRustDeviceResult>211         pub fn AddRustDevice(
212             chip_id: u32,
213             callbacks: Box<DynRustBluetoothChipCallbacks>,
214             string_type: &CxxString,
215             address: &CxxString,
216         ) -> Box<AddRustDeviceResult>;
217 
218         /// The provided address must be 6 bytes in length
219         #[rust_name = bluetooth_set_rust_device_address]
220         #[namespace = "netsim::hci::facade"]
SetRustDeviceAddress(rootcanal_id: u32, address: [u8; 6])221         pub fn SetRustDeviceAddress(rootcanal_id: u32, address: [u8; 6]);
222 
223         #[rust_name = bluetooth_remove_rust_device]
224         #[namespace = "netsim::hci::facade"]
RemoveRustDevice(rootcanal_id: u32)225         pub fn RemoveRustDevice(rootcanal_id: u32);
226 
227         #[rust_name = bluetooth_start]
228         #[namespace = "netsim::hci::facade"]
Start(proto_bytes: &[u8], instance_num: u16)229         pub fn Start(proto_bytes: &[u8], instance_num: u16);
230 
231         #[rust_name = bluetooth_stop]
232         #[namespace = "netsim::hci::facade"]
Stop()233         pub fn Stop();
234 
235         #[rust_name = add_device_to_phy]
236         #[namespace = "netsim::hci::facade"]
AddDeviceToPhy(rootcanal_id: u32, is_low_energy: bool)237         pub fn AddDeviceToPhy(rootcanal_id: u32, is_low_energy: bool);
238 
239         #[rust_name = remove_device_from_phy]
240         #[namespace = "netsim::hci::facade"]
RemoveDeviceFromPhy(rootcanal_id: u32, is_low_energy: bool)241         pub fn RemoveDeviceFromPhy(rootcanal_id: u32, is_low_energy: bool);
242     }
243 }
244 
245 #[cxx::bridge(namespace = "netsim::wifi::facade")]
246 pub mod ffi_wifi {
247     #[allow(dead_code)]
248     unsafe extern "C++" {
249         // WiFi facade.
250         include!("wifi/wifi_packet_hub.h");
251 
252         #[rust_name = handle_wifi_request]
253         #[namespace = "netsim::wifi"]
HandleWifiRequestCxx(chip_id: u32, packet: &Vec<u8>)254         fn HandleWifiRequestCxx(chip_id: u32, packet: &Vec<u8>);
255 
256         #[rust_name = hostapd_send]
257         #[namespace = "netsim::wifi"]
HostapdSendCxx(chip_id: u32, packet: &Vec<u8>)258         fn HostapdSendCxx(chip_id: u32, packet: &Vec<u8>);
259 
260         #[rust_name = libslirp_send]
261         #[namespace = "netsim::wifi"]
LibslirpSendCxx(chip_id: u32, packet: &Vec<u8>)262         fn LibslirpSendCxx(chip_id: u32, packet: &Vec<u8>);
263 
264         #[namespace = "netsim::wifi"]
libslirp_main_loop_wait()265         pub fn libslirp_main_loop_wait();
266 
267         include!("wifi/wifi_facade.h");
268 
269         #[rust_name = wifi_start]
Start(proto_bytes: &[u8])270         pub fn Start(proto_bytes: &[u8]);
271 
272         #[rust_name = wifi_stop]
Stop()273         pub fn Stop();
274 
275     }
276 
277     #[allow(unsafe_op_in_unsafe_fn)]
278     extern "Rust" {
279         #[cxx_name = HandleWiFiResponse]
handle_wifi_response(packet: &[u8])280         fn handle_wifi_response(packet: &[u8]);
281     }
282 }
283 
284 #[allow(unsafe_op_in_unsafe_fn)]
285 #[cxx::bridge(namespace = "netsim::device")]
286 pub mod ffi_devices {
287     extern "Rust" {
288 
289         // Device Resource
290         type AddChipResultCxx;
291         #[cxx_name = "GetDeviceId"]
get_device_id(self: &AddChipResultCxx) -> u32292         fn get_device_id(self: &AddChipResultCxx) -> u32;
293         #[cxx_name = "GetChipId"]
get_chip_id(self: &AddChipResultCxx) -> u32294         fn get_chip_id(self: &AddChipResultCxx) -> u32;
295         #[cxx_name = "IsError"]
is_error(self: &AddChipResultCxx) -> bool296         fn is_error(self: &AddChipResultCxx) -> bool;
297 
298         #[allow(clippy::too_many_arguments)]
299         #[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>, ) -> Box<AddChipResultCxx>300         fn add_chip_cxx(
301             device_guid: &str,
302             device_name: &str,
303             chip_kind: &CxxString,
304             chip_address: &str,
305             chip_name: &str,
306             chip_manufacturer: &str,
307             chip_product_name: &str,
308             bt_properties: &CxxVector<u8>,
309         ) -> Box<AddChipResultCxx>;
310 
311         #[cxx_name = RemoveChipCxx]
remove_chip_cxx(device_id: u32, chip_id: u32)312         fn remove_chip_cxx(device_id: u32, chip_id: u32);
313 
314         #[cxx_name = GetDistanceCxx]
get_distance_cxx(a: u32, b: u32) -> f32315         fn get_distance_cxx(a: u32, b: u32) -> f32;
316     }
317 }
318 
319 #[allow(unsafe_op_in_unsafe_fn)]
320 #[cxx::bridge(namespace = "netsim")]
321 pub mod ffi_response_writable {
322     extern "Rust" {
323         // handlers for gRPC server's invocation of API calls
324 
325         #[cxx_name = "HandleCaptureCxx"]
handle_capture_cxx( responder: Pin<&mut CxxServerResponseWriter>, method: String, param: String, body: String, )326         fn handle_capture_cxx(
327             responder: Pin<&mut CxxServerResponseWriter>,
328             method: String,
329             param: String,
330             body: String,
331         );
332 
333         #[cxx_name = "HandleDeviceCxx"]
handle_device_cxx( responder: Pin<&mut CxxServerResponseWriter>, method: String, param: String, body: String, )334         fn handle_device_cxx(
335             responder: Pin<&mut CxxServerResponseWriter>,
336             method: String,
337             param: String,
338             body: String,
339         );
340     }
341     unsafe extern "C++" {
342         /// A C++ class which can be used to respond to a request.
343         include!("frontend/server_response_writable.h");
344 
345         #[namespace = "netsim::frontend"]
346         type CxxServerResponseWriter;
347 
348         #[namespace = "netsim::frontend"]
put_ok_with_length(self: &CxxServerResponseWriter, mime_type: &CxxString, length: usize)349         fn put_ok_with_length(self: &CxxServerResponseWriter, mime_type: &CxxString, length: usize);
350 
351         #[namespace = "netsim::frontend"]
put_chunk(self: &CxxServerResponseWriter, chunk: &[u8])352         fn put_chunk(self: &CxxServerResponseWriter, chunk: &[u8]);
353 
354         #[namespace = "netsim::frontend"]
put_ok(self: &CxxServerResponseWriter, mime_type: &CxxString, body: &CxxString)355         fn put_ok(self: &CxxServerResponseWriter, mime_type: &CxxString, body: &CxxString);
356 
357         #[namespace = "netsim::frontend"]
put_error(self: &CxxServerResponseWriter, error_code: u32, error_message: &CxxString)358         fn put_error(self: &CxxServerResponseWriter, error_code: u32, error_message: &CxxString);
359 
360     }
361 }
362 
363 #[allow(unsafe_op_in_unsafe_fn)]
364 #[cxx::bridge(namespace = "netsim")]
365 pub mod ffi_util {
366     extern "Rust" {
367         // Ranging
368 
369         #[cxx_name = "DistanceToRssi"]
distance_to_rssi(tx_power: i8, distance: f32) -> i8370         fn distance_to_rssi(tx_power: i8, distance: f32) -> i8;
371 
372         // Version
373 
374         #[cxx_name = "GetVersion"]
get_version() -> String375         fn get_version() -> String;
376     }
377 
378     #[allow(dead_code)]
379     unsafe extern "C++" {
380 
381         // Crash report.
382         include!("util/crash_report.h");
383 
384         #[rust_name = set_up_crash_report]
385         #[namespace = "netsim"]
SetUpCrashReport()386         pub fn SetUpCrashReport();
387 
388         // Frontend client.
389         include!("frontend/frontend_client_stub.h");
390 
391         #[rust_name = is_netsimd_alive]
392         #[namespace = "netsim::frontend"]
IsNetsimdAlive(instance_num: u16) -> bool393         pub fn IsNetsimdAlive(instance_num: u16) -> bool;
394 
395     }
396 }
397 
398 // It's required so `RustBluetoothChip` can be sent between threads safely.
399 // Ref: How to use opaque types in threads? https://github.com/dtolnay/cxx/issues/1175
400 // SAFETY: Nothing in `RustBluetoothChip` depends on being run on a particular thread.
401 unsafe impl Send for ffi_bluetooth::RustBluetoothChip {}
402 
403 type DynRustBluetoothChipCallbacks = Box<dyn RustBluetoothChipCallbacks>;
404 
tick(dyn_callbacks: &mut DynRustBluetoothChipCallbacks)405 fn tick(dyn_callbacks: &mut DynRustBluetoothChipCallbacks) {
406     (**dyn_callbacks).tick();
407 }
408 
receive_link_layer_packet( dyn_callbacks: &mut DynRustBluetoothChipCallbacks, source_address: String, destination_address: String, packet_type: u8, packet: &[u8], )409 fn receive_link_layer_packet(
410     dyn_callbacks: &mut DynRustBluetoothChipCallbacks,
411     source_address: String,
412     destination_address: String,
413     packet_type: u8,
414     packet: &[u8],
415 ) {
416     (**dyn_callbacks).receive_link_layer_packet(
417         source_address,
418         destination_address,
419         packet_type,
420         packet,
421     );
422 }
423 
424 /// CxxServerResponseWriter is defined in server_response_writable.h
425 /// Wrapper struct allows the impl to discover the respective C++ methods
426 pub struct CxxServerResponseWriterWrapper<'a> {
427     pub writer: Pin<&'a mut ffi_response_writable::CxxServerResponseWriter>,
428 }
429 
430 impl ServerResponseWritable for CxxServerResponseWriterWrapper<'_> {
put_ok_with_length(&mut self, mime_type: &str, length: usize, _headers: StrHeaders)431     fn put_ok_with_length(&mut self, mime_type: &str, length: usize, _headers: StrHeaders) {
432         let_cxx_string!(mime_type = mime_type);
433         self.writer.put_ok_with_length(&mime_type, length);
434     }
put_chunk(&mut self, chunk: &[u8])435     fn put_chunk(&mut self, chunk: &[u8]) {
436         self.writer.put_chunk(chunk);
437     }
put_ok(&mut self, mime_type: &str, body: &str, _headers: StrHeaders)438     fn put_ok(&mut self, mime_type: &str, body: &str, _headers: StrHeaders) {
439         let_cxx_string!(mime_type = mime_type);
440         let_cxx_string!(body = body);
441         self.writer.put_ok(&mime_type, &body);
442     }
put_error(&mut self, error_code: u16, error_message: &str)443     fn put_error(&mut self, error_code: u16, error_message: &str) {
444         let_cxx_string!(error_message = error_message);
445         self.writer.put_error(error_code.into(), &error_message);
446     }
447 
put_ok_with_vec(&mut self, _mime_type: &str, _body: Vec<u8>, _headers: StrHeaders)448     fn put_ok_with_vec(&mut self, _mime_type: &str, _body: Vec<u8>, _headers: StrHeaders) {
449         todo!()
450     }
put_ok_switch_protocol(&mut self, _connection: &str, _headers: StrHeaders)451     fn put_ok_switch_protocol(&mut self, _connection: &str, _headers: StrHeaders) {
452         todo!()
453     }
454 }
455