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 use super::h4::PacketError;
16 use crate::devices::chip::{self, ChipIdentifier};
17 use crate::devices::devices_handler::{add_chip, remove_chip};
18 use crate::transport::h4;
19 use crate::wireless;
20 use crate::wireless::packet::{register_transport, unregister_transport, Response};
21 use bytes::Bytes;
22 use log::{error, info, warn};
23 use netsim_proto::common::ChipKind;
24 use netsim_proto::startup::DeviceInfo as ProtoDeviceInfo;
25 use std::io::{ErrorKind, Write};
26 use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, TcpListener, TcpStream};
27 use std::thread;
28
29 // The HCI server implements the Bluetooth UART transport protocol
30 // (a.k.a. H4) over TCP. Each new connection on the HCI port spawns a
31 // new virtual controller associated with a new device.
32
33 /// Start the socket-based transport.
34 ///
35 /// The socket transport reads/writes host-controller messages
36 /// for bluetooth (h4 hci) over a [TcpStream] transport.
37 ///
38
39 struct SocketTransport {
40 stream: TcpStream,
41 }
42
43 impl Response for SocketTransport {
response(&mut self, packet: Bytes, packet_type: u8)44 fn response(&mut self, packet: Bytes, packet_type: u8) {
45 let mut buffer = Vec::new();
46 buffer.push(packet_type);
47 buffer.extend(packet);
48 if let Err(e) = self.stream.write_all(&buffer[..]) {
49 error!("error writing {}", e);
50 };
51 }
52 }
53
run_socket_transport(hci_port: u16)54 pub fn run_socket_transport(hci_port: u16) {
55 thread::Builder::new()
56 .name("hci_transport".to_string())
57 .spawn(move || {
58 accept_incoming(hci_port)
59 .unwrap_or_else(|e| error!("Failed to accept incoming stream: {:?}", e));
60 })
61 .unwrap();
62 }
63
accept_incoming(hci_port: u16) -> std::io::Result<()>64 fn accept_incoming(hci_port: u16) -> std::io::Result<()> {
65 let listener = TcpListener::bind(SocketAddr::from((Ipv4Addr::LOCALHOST, hci_port))).or_else(|e| {
66 warn!("Failed to bind to 127.0.0.1:{hci_port} in netsimd socket server, Trying [::1]:{hci_port}. {e:?}");
67 TcpListener::bind(SocketAddr::from((Ipv6Addr::LOCALHOST, hci_port)))
68 }
69 )?;
70 info!("Hci socket server is listening on: {}", hci_port);
71
72 for stream in listener.incoming() {
73 let stream = stream?;
74 // the socket address of the remote peer of this TCP connection
75 info!("Hci client address: {}", stream.peer_addr().unwrap());
76 thread::Builder::new()
77 .name("hci_transport client".to_string())
78 .spawn(move || {
79 handle_hci_client(stream);
80 })
81 .unwrap();
82 }
83 Ok(())
84 }
85
handle_hci_client(stream: TcpStream)86 fn handle_hci_client(stream: TcpStream) {
87 // ...
88 let chip_create_params = chip::CreateParams {
89 kind: ChipKind::BLUETOOTH,
90 address: String::new(),
91 name: Some(format!("socket-{}", stream.peer_addr().unwrap())),
92 manufacturer: "Google".to_string(),
93 product_name: "Google".to_string(),
94 };
95 #[cfg(not(test))]
96 let wireless_create_params =
97 wireless::CreateParam::Bluetooth(wireless::bluetooth::CreateParams {
98 address: String::new(),
99 bt_properties: None,
100 });
101 #[cfg(test)]
102 let wireless_create_params = wireless::CreateParam::Mock(wireless::mocked::CreateParams {
103 chip_kind: ChipKind::BLUETOOTH,
104 });
105 let device_info = ProtoDeviceInfo { kind: "HCI_SOCKET".to_string(), ..Default::default() };
106 let result = match add_chip(
107 &stream.peer_addr().unwrap().port().to_string(),
108 &format!("socket-{}", stream.peer_addr().unwrap()),
109 &chip_create_params,
110 &wireless_create_params,
111 device_info,
112 ) {
113 Ok(chip_result) => chip_result,
114 Err(err) => {
115 warn!("{err}");
116 return;
117 }
118 };
119 let tcp_rx = stream.try_clone().unwrap();
120 register_transport(result.chip_id, Box::new(SocketTransport { stream }));
121
122 let _ = reader(tcp_rx, ChipKind::BLUETOOTH, result.chip_id);
123
124 // unregister before remove_chip because facade may re-use facade_id
125 // on an intertwining create_chip and the unregister here might remove
126 // the recently added chip creating a disconnected transport.
127 unregister_transport(result.chip_id);
128
129 if let Err(err) = remove_chip(result.device_id, result.chip_id) {
130 warn!("{err}");
131 };
132 info!("Removed chip: device_id: {} chip_id: {}.", result.device_id, result.chip_id);
133 }
134
135 /// read from the socket and pass to the packet hub.
136 ///
reader(mut tcp_rx: TcpStream, kind: ChipKind, chip_id: ChipIdentifier) -> std::io::Result<()>137 fn reader(mut tcp_rx: TcpStream, kind: ChipKind, chip_id: ChipIdentifier) -> std::io::Result<()> {
138 loop {
139 if let ChipKind::BLUETOOTH = kind {
140 match h4::read_h4_packet(&mut tcp_rx) {
141 Ok(packet) => {
142 wireless::handle_request(chip_id, &packet.payload, packet.h4_type);
143 }
144 Err(PacketError::IoError(e)) if e.kind() == ErrorKind::UnexpectedEof => {
145 info!("End socket reader connection with {}.", &tcp_rx.peer_addr().unwrap());
146 return Ok(());
147 }
148 Err(e) => {
149 error!("End socket reader connection with {}. Failed to reading hci control packet: {:?}", &tcp_rx.peer_addr().unwrap(), e);
150 return Ok(());
151 }
152 }
153 }
154 }
155 }
156