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