1*cf78ab8cSAndroid Build Coastguard Worker // Copyright 2023 Google LLC
2*cf78ab8cSAndroid Build Coastguard Worker //
3*cf78ab8cSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*cf78ab8cSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*cf78ab8cSAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*cf78ab8cSAndroid Build Coastguard Worker //
7*cf78ab8cSAndroid Build Coastguard Worker // https://www.apache.org/licenses/LICENSE-2.0
8*cf78ab8cSAndroid Build Coastguard Worker //
9*cf78ab8cSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*cf78ab8cSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*cf78ab8cSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*cf78ab8cSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*cf78ab8cSAndroid Build Coastguard Worker // limitations under the License.
14*cf78ab8cSAndroid Build Coastguard Worker
15*cf78ab8cSAndroid Build Coastguard Worker use crate::bluetooth::advertise_settings as ble_advertise_settings;
16*cf78ab8cSAndroid Build Coastguard Worker use crate::captures::captures_handler::clear_pcap_files;
17*cf78ab8cSAndroid Build Coastguard Worker use crate::http_server::server::run_http_server;
18*cf78ab8cSAndroid Build Coastguard Worker use crate::transport::socket::run_socket_transport;
19*cf78ab8cSAndroid Build Coastguard Worker use crate::wireless;
20*cf78ab8cSAndroid Build Coastguard Worker use log::{error, info, warn};
21*cf78ab8cSAndroid Build Coastguard Worker use netsim_common::util::ini_file::IniFile;
22*cf78ab8cSAndroid Build Coastguard Worker use netsim_common::util::os_utils::get_netsim_ini_filepath;
23*cf78ab8cSAndroid Build Coastguard Worker use netsim_common::util::zip_artifact::remove_zip_files;
24*cf78ab8cSAndroid Build Coastguard Worker use std::env;
25*cf78ab8cSAndroid Build Coastguard Worker use std::time::Duration;
26*cf78ab8cSAndroid Build Coastguard Worker
27*cf78ab8cSAndroid Build Coastguard Worker /// Module to control startup, run, and cleanup netsimd services.
28*cf78ab8cSAndroid Build Coastguard Worker
29*cf78ab8cSAndroid Build Coastguard Worker pub struct ServiceParams {
30*cf78ab8cSAndroid Build Coastguard Worker fd_startup_str: String,
31*cf78ab8cSAndroid Build Coastguard Worker no_cli_ui: bool,
32*cf78ab8cSAndroid Build Coastguard Worker no_web_ui: bool,
33*cf78ab8cSAndroid Build Coastguard Worker hci_port: u16,
34*cf78ab8cSAndroid Build Coastguard Worker instance_num: u16,
35*cf78ab8cSAndroid Build Coastguard Worker dev: bool,
36*cf78ab8cSAndroid Build Coastguard Worker vsock: u16,
37*cf78ab8cSAndroid Build Coastguard Worker }
38*cf78ab8cSAndroid Build Coastguard Worker
39*cf78ab8cSAndroid Build Coastguard Worker impl ServiceParams {
40*cf78ab8cSAndroid Build Coastguard Worker #[allow(clippy::too_many_arguments)]
new( fd_startup_str: String, no_cli_ui: bool, no_web_ui: bool, hci_port: u16, instance_num: u16, dev: bool, vsock: u16, ) -> Self41*cf78ab8cSAndroid Build Coastguard Worker pub fn new(
42*cf78ab8cSAndroid Build Coastguard Worker fd_startup_str: String,
43*cf78ab8cSAndroid Build Coastguard Worker no_cli_ui: bool,
44*cf78ab8cSAndroid Build Coastguard Worker no_web_ui: bool,
45*cf78ab8cSAndroid Build Coastguard Worker hci_port: u16,
46*cf78ab8cSAndroid Build Coastguard Worker instance_num: u16,
47*cf78ab8cSAndroid Build Coastguard Worker dev: bool,
48*cf78ab8cSAndroid Build Coastguard Worker vsock: u16,
49*cf78ab8cSAndroid Build Coastguard Worker ) -> Self {
50*cf78ab8cSAndroid Build Coastguard Worker ServiceParams { fd_startup_str, no_cli_ui, no_web_ui, hci_port, instance_num, dev, vsock }
51*cf78ab8cSAndroid Build Coastguard Worker }
52*cf78ab8cSAndroid Build Coastguard Worker }
53*cf78ab8cSAndroid Build Coastguard Worker
54*cf78ab8cSAndroid Build Coastguard Worker pub struct Service {
55*cf78ab8cSAndroid Build Coastguard Worker // netsimd states, like device resource.
56*cf78ab8cSAndroid Build Coastguard Worker service_params: ServiceParams,
57*cf78ab8cSAndroid Build Coastguard Worker grpc_server: Option<grpcio::Server>,
58*cf78ab8cSAndroid Build Coastguard Worker }
59*cf78ab8cSAndroid Build Coastguard Worker
60*cf78ab8cSAndroid Build Coastguard Worker impl Service {
61*cf78ab8cSAndroid Build Coastguard Worker /// # Safety
62*cf78ab8cSAndroid Build Coastguard Worker ///
63*cf78ab8cSAndroid Build Coastguard Worker /// The file descriptors in `service_params.fd_startup_str` must be valid and open, and must
64*cf78ab8cSAndroid Build Coastguard Worker /// remain so for as long as the `Service` exists.
new(service_params: ServiceParams) -> Service65*cf78ab8cSAndroid Build Coastguard Worker pub unsafe fn new(service_params: ServiceParams) -> Service {
66*cf78ab8cSAndroid Build Coastguard Worker Service { service_params, grpc_server: None }
67*cf78ab8cSAndroid Build Coastguard Worker }
68*cf78ab8cSAndroid Build Coastguard Worker
69*cf78ab8cSAndroid Build Coastguard Worker /// Sets up the states for netsimd.
set_up(&self)70*cf78ab8cSAndroid Build Coastguard Worker pub fn set_up(&self) {
71*cf78ab8cSAndroid Build Coastguard Worker // Clear all zip files
72*cf78ab8cSAndroid Build Coastguard Worker match remove_zip_files() {
73*cf78ab8cSAndroid Build Coastguard Worker Ok(()) => info!("netsim generated zip files in temp directory has been removed."),
74*cf78ab8cSAndroid Build Coastguard Worker Err(err) => error!("{err:?}"),
75*cf78ab8cSAndroid Build Coastguard Worker }
76*cf78ab8cSAndroid Build Coastguard Worker
77*cf78ab8cSAndroid Build Coastguard Worker // Clear all pcap files
78*cf78ab8cSAndroid Build Coastguard Worker if clear_pcap_files() {
79*cf78ab8cSAndroid Build Coastguard Worker info!("netsim generated pcap files in temp directory has been removed.");
80*cf78ab8cSAndroid Build Coastguard Worker }
81*cf78ab8cSAndroid Build Coastguard Worker }
82*cf78ab8cSAndroid Build Coastguard Worker
83*cf78ab8cSAndroid Build Coastguard Worker /// Runs netsim gRPC server
run_grpc_server(&mut self) -> anyhow::Result<u32>84*cf78ab8cSAndroid Build Coastguard Worker fn run_grpc_server(&mut self) -> anyhow::Result<u32> {
85*cf78ab8cSAndroid Build Coastguard Worker // If NETSIM_GRPC_PORT is set, use the fixed port for grpc server.
86*cf78ab8cSAndroid Build Coastguard Worker let mut netsim_grpc_port =
87*cf78ab8cSAndroid Build Coastguard Worker env::var("NETSIM_GRPC_PORT").map(|val| val.parse::<u32>().unwrap_or(0)).unwrap_or(0);
88*cf78ab8cSAndroid Build Coastguard Worker // Run netsim gRPC server
89*cf78ab8cSAndroid Build Coastguard Worker let (server, port) = crate::grpc_server::server::start(
90*cf78ab8cSAndroid Build Coastguard Worker netsim_grpc_port,
91*cf78ab8cSAndroid Build Coastguard Worker self.service_params.no_cli_ui,
92*cf78ab8cSAndroid Build Coastguard Worker self.service_params.vsock,
93*cf78ab8cSAndroid Build Coastguard Worker )?;
94*cf78ab8cSAndroid Build Coastguard Worker self.grpc_server = Some(server);
95*cf78ab8cSAndroid Build Coastguard Worker netsim_grpc_port = port.into();
96*cf78ab8cSAndroid Build Coastguard Worker Ok(netsim_grpc_port)
97*cf78ab8cSAndroid Build Coastguard Worker }
98*cf78ab8cSAndroid Build Coastguard Worker
99*cf78ab8cSAndroid Build Coastguard Worker /// Runs netsim web server
run_web_server(&self) -> Option<u16>100*cf78ab8cSAndroid Build Coastguard Worker fn run_web_server(&self) -> Option<u16> {
101*cf78ab8cSAndroid Build Coastguard Worker // If NETSIM_NO_WEB_SERVER is set, don't start http server.
102*cf78ab8cSAndroid Build Coastguard Worker let no_web_server = env::var("NETSIM_NO_WEB_SERVER").is_ok_and(|v| v == "1");
103*cf78ab8cSAndroid Build Coastguard Worker match !no_web_server && !self.service_params.no_web_ui {
104*cf78ab8cSAndroid Build Coastguard Worker true => {
105*cf78ab8cSAndroid Build Coastguard Worker Some(run_http_server(self.service_params.instance_num, self.service_params.dev))
106*cf78ab8cSAndroid Build Coastguard Worker }
107*cf78ab8cSAndroid Build Coastguard Worker false => None,
108*cf78ab8cSAndroid Build Coastguard Worker }
109*cf78ab8cSAndroid Build Coastguard Worker }
110*cf78ab8cSAndroid Build Coastguard Worker
111*cf78ab8cSAndroid Build Coastguard Worker /// Write ports to netsim.ini file
write_ports_to_ini(&self, grpc_port: u32, web_port: Option<u16>)112*cf78ab8cSAndroid Build Coastguard Worker fn write_ports_to_ini(&self, grpc_port: u32, web_port: Option<u16>) {
113*cf78ab8cSAndroid Build Coastguard Worker let filepath = get_netsim_ini_filepath(self.service_params.instance_num);
114*cf78ab8cSAndroid Build Coastguard Worker let mut ini_file = IniFile::new(filepath);
115*cf78ab8cSAndroid Build Coastguard Worker if let Some(num) = web_port {
116*cf78ab8cSAndroid Build Coastguard Worker ini_file.insert("web.port", &num.to_string());
117*cf78ab8cSAndroid Build Coastguard Worker }
118*cf78ab8cSAndroid Build Coastguard Worker ini_file.insert("grpc.port", &grpc_port.to_string());
119*cf78ab8cSAndroid Build Coastguard Worker if let Err(err) = ini_file.write() {
120*cf78ab8cSAndroid Build Coastguard Worker error!("{err:?}");
121*cf78ab8cSAndroid Build Coastguard Worker }
122*cf78ab8cSAndroid Build Coastguard Worker }
123*cf78ab8cSAndroid Build Coastguard Worker
124*cf78ab8cSAndroid Build Coastguard Worker /// Runs the netsimd services.
125*cf78ab8cSAndroid Build Coastguard Worker #[allow(unused_unsafe)]
run(&mut self)126*cf78ab8cSAndroid Build Coastguard Worker pub fn run(&mut self) {
127*cf78ab8cSAndroid Build Coastguard Worker if !self.service_params.fd_startup_str.is_empty() {
128*cf78ab8cSAndroid Build Coastguard Worker // SAFETY: When the `Service` was constructed by `Service::new` the caller guaranteed
129*cf78ab8cSAndroid Build Coastguard Worker // that the file descriptors in `service_params.fd_startup_str` would remain valid and
130*cf78ab8cSAndroid Build Coastguard Worker // open.
131*cf78ab8cSAndroid Build Coastguard Worker unsafe {
132*cf78ab8cSAndroid Build Coastguard Worker use crate::transport::fd::run_fd_transport;
133*cf78ab8cSAndroid Build Coastguard Worker run_fd_transport(&self.service_params.fd_startup_str);
134*cf78ab8cSAndroid Build Coastguard Worker }
135*cf78ab8cSAndroid Build Coastguard Worker }
136*cf78ab8cSAndroid Build Coastguard Worker
137*cf78ab8cSAndroid Build Coastguard Worker let grpc_port = match self.run_grpc_server() {
138*cf78ab8cSAndroid Build Coastguard Worker Ok(port) => port,
139*cf78ab8cSAndroid Build Coastguard Worker Err(e) => {
140*cf78ab8cSAndroid Build Coastguard Worker error!("Failed to run netsimd: {e:?}");
141*cf78ab8cSAndroid Build Coastguard Worker return;
142*cf78ab8cSAndroid Build Coastguard Worker }
143*cf78ab8cSAndroid Build Coastguard Worker };
144*cf78ab8cSAndroid Build Coastguard Worker
145*cf78ab8cSAndroid Build Coastguard Worker // Run frontend web server
146*cf78ab8cSAndroid Build Coastguard Worker let web_port = self.run_web_server();
147*cf78ab8cSAndroid Build Coastguard Worker
148*cf78ab8cSAndroid Build Coastguard Worker // Write the port numbers to ini file
149*cf78ab8cSAndroid Build Coastguard Worker self.write_ports_to_ini(grpc_port, web_port);
150*cf78ab8cSAndroid Build Coastguard Worker
151*cf78ab8cSAndroid Build Coastguard Worker // Run the socket server.
152*cf78ab8cSAndroid Build Coastguard Worker run_socket_transport(self.service_params.hci_port);
153*cf78ab8cSAndroid Build Coastguard Worker }
154*cf78ab8cSAndroid Build Coastguard Worker
155*cf78ab8cSAndroid Build Coastguard Worker /// Shut down the netsimd services
shut_down(&mut self)156*cf78ab8cSAndroid Build Coastguard Worker pub fn shut_down(&mut self) {
157*cf78ab8cSAndroid Build Coastguard Worker // TODO: shutdown other services in Rust
158*cf78ab8cSAndroid Build Coastguard Worker self.grpc_server.as_mut().map(|server| server.shutdown());
159*cf78ab8cSAndroid Build Coastguard Worker wireless::bluetooth::bluetooth_stop();
160*cf78ab8cSAndroid Build Coastguard Worker wireless::wifi::wifi_stop();
161*cf78ab8cSAndroid Build Coastguard Worker }
162*cf78ab8cSAndroid Build Coastguard Worker }
163*cf78ab8cSAndroid Build Coastguard Worker
164*cf78ab8cSAndroid Build Coastguard Worker /// Constructing test beacons for dev mode
new_test_beacon(idx: u32, interval: u64)165*cf78ab8cSAndroid Build Coastguard Worker pub fn new_test_beacon(idx: u32, interval: u64) {
166*cf78ab8cSAndroid Build Coastguard Worker use crate::devices::devices_handler::create_device;
167*cf78ab8cSAndroid Build Coastguard Worker use netsim_proto::common::ChipKind;
168*cf78ab8cSAndroid Build Coastguard Worker use netsim_proto::frontend::CreateDeviceRequest;
169*cf78ab8cSAndroid Build Coastguard Worker use netsim_proto::model::chip::ble_beacon::{
170*cf78ab8cSAndroid Build Coastguard Worker AdvertiseData as AdvertiseDataProto, AdvertiseSettings as AdvertiseSettingsProto,
171*cf78ab8cSAndroid Build Coastguard Worker };
172*cf78ab8cSAndroid Build Coastguard Worker use netsim_proto::model::chip_create::{
173*cf78ab8cSAndroid Build Coastguard Worker BleBeaconCreate as BleBeaconCreateProto, Chip as ChipProto,
174*cf78ab8cSAndroid Build Coastguard Worker };
175*cf78ab8cSAndroid Build Coastguard Worker use netsim_proto::model::ChipCreate as ChipCreateProto;
176*cf78ab8cSAndroid Build Coastguard Worker use netsim_proto::model::DeviceCreate as DeviceCreateProto;
177*cf78ab8cSAndroid Build Coastguard Worker use protobuf::MessageField;
178*cf78ab8cSAndroid Build Coastguard Worker
179*cf78ab8cSAndroid Build Coastguard Worker let beacon_proto = BleBeaconCreateProto {
180*cf78ab8cSAndroid Build Coastguard Worker address: format!("be:ac:01:be:ef:{:02x}", idx),
181*cf78ab8cSAndroid Build Coastguard Worker settings: MessageField::some(AdvertiseSettingsProto {
182*cf78ab8cSAndroid Build Coastguard Worker interval: Some(
183*cf78ab8cSAndroid Build Coastguard Worker ble_advertise_settings::AdvertiseMode::new(Duration::from_millis(interval))
184*cf78ab8cSAndroid Build Coastguard Worker .try_into()
185*cf78ab8cSAndroid Build Coastguard Worker .unwrap(),
186*cf78ab8cSAndroid Build Coastguard Worker ),
187*cf78ab8cSAndroid Build Coastguard Worker scannable: true,
188*cf78ab8cSAndroid Build Coastguard Worker ..Default::default()
189*cf78ab8cSAndroid Build Coastguard Worker }),
190*cf78ab8cSAndroid Build Coastguard Worker adv_data: MessageField::some(AdvertiseDataProto {
191*cf78ab8cSAndroid Build Coastguard Worker include_device_name: true,
192*cf78ab8cSAndroid Build Coastguard Worker ..Default::default()
193*cf78ab8cSAndroid Build Coastguard Worker }),
194*cf78ab8cSAndroid Build Coastguard Worker scan_response: MessageField::some(AdvertiseDataProto {
195*cf78ab8cSAndroid Build Coastguard Worker manufacturer_data: vec![1u8, 2, 3, 4],
196*cf78ab8cSAndroid Build Coastguard Worker ..Default::default()
197*cf78ab8cSAndroid Build Coastguard Worker }),
198*cf78ab8cSAndroid Build Coastguard Worker ..Default::default()
199*cf78ab8cSAndroid Build Coastguard Worker };
200*cf78ab8cSAndroid Build Coastguard Worker
201*cf78ab8cSAndroid Build Coastguard Worker let chip_proto = ChipCreateProto {
202*cf78ab8cSAndroid Build Coastguard Worker name: format!("gDevice-bt-beacon-chip-{idx}"),
203*cf78ab8cSAndroid Build Coastguard Worker kind: ChipKind::BLUETOOTH_BEACON.into(),
204*cf78ab8cSAndroid Build Coastguard Worker chip: Some(ChipProto::BleBeacon(beacon_proto)),
205*cf78ab8cSAndroid Build Coastguard Worker ..Default::default()
206*cf78ab8cSAndroid Build Coastguard Worker };
207*cf78ab8cSAndroid Build Coastguard Worker
208*cf78ab8cSAndroid Build Coastguard Worker let device_proto = DeviceCreateProto {
209*cf78ab8cSAndroid Build Coastguard Worker name: format!("gDevice-beacon-{idx}"),
210*cf78ab8cSAndroid Build Coastguard Worker chips: vec![chip_proto],
211*cf78ab8cSAndroid Build Coastguard Worker ..Default::default()
212*cf78ab8cSAndroid Build Coastguard Worker };
213*cf78ab8cSAndroid Build Coastguard Worker
214*cf78ab8cSAndroid Build Coastguard Worker let request =
215*cf78ab8cSAndroid Build Coastguard Worker CreateDeviceRequest { device: MessageField::some(device_proto), ..Default::default() };
216*cf78ab8cSAndroid Build Coastguard Worker
217*cf78ab8cSAndroid Build Coastguard Worker if let Err(err) = create_device(&request) {
218*cf78ab8cSAndroid Build Coastguard Worker warn!("Failed to create beacon device {idx}: {err}");
219*cf78ab8cSAndroid Build Coastguard Worker }
220*cf78ab8cSAndroid Build Coastguard Worker }
221