blob: 2960a496543d4f4f989e4c6194f45e441ae03c09 [file] [log] [blame]
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use clap::Parser;
use log::warn;
#[cfg(feature = "cuttlefish")]
use log::{error, info};
use netsim_common::util::netsim_logger;
use crate::args::NetsimdArgs;
use crate::ffi::ffi_util;
use crate::service::{Service, ServiceParams};
#[cfg(feature = "cuttlefish")]
use netsim_common::util::os_utils::get_server_address;
use std::ffi::{c_char, c_int};
/// Wireless network simulator for android (and other) emulated devices.
///
/// # Safety
///
/// The file descriptors passed in `NetsimdArgs::fd_startup_str` must remain valid and open for as
/// long as the program runs.
#[no_mangle]
pub unsafe extern "C" fn rust_main(argc: c_int, argv: *const *const c_char) {
ffi_util::set_up_crash_report();
netsim_logger::init("netsimd");
let netsimd_args = get_netsimd_args(argc, argv);
run_netsimd_with_args(netsimd_args);
}
#[allow(unused)]
fn get_netsimd_args(argc: c_int, argv: *const *const c_char) -> NetsimdArgs {
#[cfg(feature = "cuttlefish")]
{
// TODO: Use NetsimdArgs::parse() after netsimd binary is built with netsimd.rs.
// In linux arm64 in aosp-main, it can't access CLI arguments by std::env::args() with netsimd.cc wrapper.
let argv: Vec<_> = (0..argc)
.map(|i|
// SAFETY: argc and argv will remain valid as long as the program runs.
unsafe {
std::ffi::CStr::from_ptr(*argv.add(i as usize)).to_str().unwrap().to_owned()
})
.collect();
NetsimdArgs::parse_from(argv)
}
#[cfg(not(feature = "cuttlefish"))]
NetsimdArgs::parse()
}
fn run_netsimd_with_args(args: NetsimdArgs) {
// Redirect stdout and stderr to files only if netsimd is not invoked
// by Cuttlefish. Some Cuttlefish builds fail when writing logs to files.
#[cfg(not(feature = "cuttlefish"))]
if !args.logtostderr {
cxx::let_cxx_string!(netsimd_temp_dir = netsim_common::system::netsimd_temp_dir_string());
ffi_util::redirect_std_stream(&netsimd_temp_dir);
}
match args.connector_instance {
#[cfg(feature = "cuttlefish")]
Some(connector_instance) => run_netsimd_connector(args, connector_instance),
_ => run_netsimd_primary(args),
}
}
/// Forwards packets to another netsim daemon.
#[cfg(feature = "cuttlefish")]
fn run_netsimd_connector(args: NetsimdArgs, instance: u16) {
let fd_startup = match args.fd_startup_str {
None => {
error!("Failed to start netsimd forwarder, missing `-s` arg");
return;
}
Some(fd_startup) => fd_startup,
};
info!("Starting netsim daemon in forwarding mode");
// TODO: Make this function returns Result to use `?` instead of unwrap().
let server = get_server_address(instance)
.map(|port| format!("localhost:{}", port))
.ok_or_else(|| warn!("Unable to find server address for instance {}", instance))
.unwrap();
crate::transport::fd::run_fd_connector(&fd_startup, server.as_str())
.map_err(|e| error!("Failed to run fd connector: {}", e))
.unwrap();
}
fn run_netsimd_primary(netsimd_args: NetsimdArgs) {
let fd_startup_str = netsimd_args.fd_startup_str.unwrap_or_default();
let no_cli_ui = netsimd_args.no_cli_ui;
let no_web_ui = netsimd_args.no_web_ui;
let pcap = netsimd_args.pcap;
let disable_address_reuse = netsimd_args.disable_address_reuse;
let instance_num = ffi_util::get_instance(netsimd_args.instance.unwrap_or_default());
let hci_port: u16 =
ffi_util::get_hci_port(netsimd_args.hci_port.unwrap_or_default(), instance_num)
.try_into()
.unwrap();
let dev = netsimd_args.dev;
let vsock = netsimd_args.vsock.unwrap_or_default();
#[cfg(feature = "cuttlefish")]
if fd_startup_str.is_empty() {
warn!("Failed to start netsim daemon because fd startup flag `-s` is empty");
return;
}
if ffi_util::is_netsimd_alive(instance_num) {
warn!("Failed to start netsim daemon because a netsim daemon is already running");
return;
}
let service_params = ServiceParams::new(
fd_startup_str,
no_cli_ui,
no_web_ui,
pcap,
disable_address_reuse,
hci_port,
instance_num,
dev,
vsock,
);
// SAFETY: The caller guaranteed that the file descriptors in `fd_startup_str` would remain
// valid and open for as long as the program runs.
let service = unsafe { Service::new(service_params) };
service.set_up();
service.run();
}