1 //! Starts the facade services that allow us to test the Bluetooth stack
2 
3 #[macro_use]
4 extern crate clap;
5 use clap::{App, Arg};
6 
7 #[macro_use]
8 extern crate lazy_static;
9 
10 use bluetooth_with_facades::RootFacadeService;
11 use futures::channel::mpsc;
12 use futures::executor::block_on;
13 use futures::stream::StreamExt;
14 use grpcio::*;
15 use log::debug;
16 use nix::sys::signal;
17 use std::net::{IpAddr, Ipv4Addr, SocketAddr};
18 use std::sync::{Arc, Mutex};
19 use tokio::io::AsyncWriteExt;
20 use tokio::net::TcpStream;
21 use tokio::runtime::Runtime;
22 
main()23 fn main() {
24     let sigint = install_sigint();
25     bt_common::init_logging();
26     let rt = Arc::new(Runtime::new().unwrap());
27     rt.block_on(async_main(Arc::clone(&rt), sigint));
28 }
29 
async_main(rt: Arc<Runtime>, mut sigint: mpsc::UnboundedReceiver<()>)30 async fn async_main(rt: Arc<Runtime>, mut sigint: mpsc::UnboundedReceiver<()>) {
31     let matches = App::new("bluetooth_with_facades")
32         .about("The bluetooth stack, with testing facades enabled and exposed via gRPC.")
33         .arg(
34             Arg::with_name("root-server-port")
35                 .long("root-server-port")
36                 .default_value("8897")
37                 .takes_value(true),
38         )
39         .arg(Arg::with_name("grpc-port").long("grpc-port").default_value("8899").takes_value(true))
40         .arg(
41             Arg::with_name("signal-port")
42                 .long("signal-port")
43                 .default_value("8895")
44                 .takes_value(true),
45         )
46         .arg(Arg::with_name("rootcanal-port").long("rootcanal-port").takes_value(true))
47         .arg(Arg::with_name("btsnoop").long("btsnoop").takes_value(true))
48         .arg(Arg::with_name("btsnooz").long("btsnooz").takes_value(true))
49         .arg(Arg::with_name("btconfig").long("btconfig").takes_value(true))
50         .get_matches();
51 
52     let root_server_port = value_t!(matches, "root-server-port", u16).unwrap();
53     let grpc_port = value_t!(matches, "grpc-port", u16).unwrap();
54     let signal_port = value_t!(matches, "signal-port", u16).unwrap();
55     let rootcanal_port = value_t!(matches, "rootcanal-port", u16).ok();
56     let env = Arc::new(Environment::new(2));
57     let mut server = ServerBuilder::new(env)
58         .register_service(RootFacadeService::create(
59             rt,
60             grpc_port,
61             rootcanal_port,
62             matches.value_of("btsnoop").map(String::from),
63         ))
64         .bind("0.0.0.0", root_server_port)
65         .build()
66         .unwrap();
67     server.start();
68 
69     indicate_started(signal_port).await;
70     sigint.next().await;
71     block_on(server.shutdown()).unwrap();
72 }
73 
indicate_started(signal_port: u16)74 async fn indicate_started(signal_port: u16) {
75     let address = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), signal_port);
76     let mut stream = TcpStream::connect(address).await.unwrap();
77     stream.shutdown().await.unwrap();
78 }
79 
80 // TODO: remove as this is a temporary nix-based hack to catch SIGINT
install_sigint() -> mpsc::UnboundedReceiver<()>81 fn install_sigint() -> mpsc::UnboundedReceiver<()> {
82     let (tx, rx) = mpsc::unbounded();
83     *SIGINT_TX.lock().unwrap() = Some(tx);
84 
85     let sig_action = signal::SigAction::new(
86         signal::SigHandler::Handler(handle_sigint),
87         signal::SaFlags::empty(),
88         signal::SigSet::empty(),
89     );
90     unsafe {
91         signal::sigaction(signal::SIGINT, &sig_action).unwrap();
92     }
93 
94     rx
95 }
96 
97 lazy_static! {
98     static ref SIGINT_TX: Mutex<Option<mpsc::UnboundedSender<()>>> = Mutex::new(None);
99 }
100 
handle_sigint(_: i32)101 extern "C" fn handle_sigint(_: i32) {
102     let mut sigint_tx = SIGINT_TX.lock().unwrap();
103     if let Some(tx) = &*sigint_tx {
104         debug!("Stopping gRPC root server due to SIGINT");
105         tx.unbounded_send(()).unwrap();
106     }
107     *sigint_tx = None;
108 }
109