• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 std::sync::{Arc, Mutex};
16 use std::{collections::HashMap, io::Cursor, net::TcpStream};
17 
18 use bytes::Bytes;
19 use http::Request;
20 use log::{error, info, warn};
21 use netsim_proto::common::ChipKind;
22 use tungstenite::{protocol::Role, Message, WebSocket};
23 
24 use crate::devices::chip;
25 use crate::devices::devices_handler::{add_chip, remove_chip};
26 use crate::http_server::server_response::ResponseWritable;
27 use crate::wireless;
28 use crate::wireless::packet::{register_transport, unregister_transport, Response};
29 
30 use super::h4;
31 
32 // This feature is enabled only for CMake builds
33 #[cfg(feature = "local_ssl")]
34 use crate::openssl;
35 
36 /// Generate Sec-Websocket-Accept value from given Sec-Websocket-Key value
generate_websocket_accept(websocket_key: String) -> String37 fn generate_websocket_accept(websocket_key: String) -> String {
38     let concat = websocket_key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
39     let hashed = openssl::sha::sha1(concat.as_bytes());
40     data_encoding::BASE64.encode(&hashed)
41 }
42 
43 /// Handler for websocket server connection
handle_websocket(request: &Request<Vec<u8>>, param: &str, writer: ResponseWritable)44 pub fn handle_websocket(request: &Request<Vec<u8>>, param: &str, writer: ResponseWritable) {
45     if param != "bt" {
46         writer.put_error(404, "netsim websocket currently supports bt, uri=/v1/websocket/bt");
47     }
48     let websocket_accept = match request.headers().get("Sec-Websocket-Key") {
49         Some(key) => match key.to_str() {
50             Ok(key_str) => generate_websocket_accept(key_str.to_string()),
51             Err(_) => {
52                 writer.put_error(
53                     404,
54                     "The HeaderValue of Sec-Websocket-Key cannot be converted to str",
55                 );
56                 return;
57             }
58         },
59         None => {
60             writer.put_error(404, "Missing Sec-Websocket-Key in header");
61             return;
62         }
63     };
64     writer.put_ok_switch_protocol(
65         "websocket",
66         vec![("Sec-WebSocket-Accept".to_string(), websocket_accept)],
67     )
68 }
69 
70 struct WebSocketTransport {
71     websocket_writer: Arc<Mutex<WebSocket<TcpStream>>>,
72 }
73 
74 impl Response for WebSocketTransport {
response(&mut self, packet: Bytes, packet_type: u8)75     fn response(&mut self, packet: Bytes, packet_type: u8) {
76         let mut buffer = Vec::new();
77         buffer.push(packet_type);
78         buffer.extend(packet);
79         if let Err(err) = self
80             .websocket_writer
81             .lock()
82             .expect("Failed to acquire lock on WebSocket")
83             .send(Message::Binary(buffer))
84         {
85             error!("{err}");
86         };
87     }
88 }
89 
90 /// Run websocket transport for packet flow in netsim
run_websocket_transport(stream: TcpStream, queries: HashMap<&str, &str>)91 pub fn run_websocket_transport(stream: TcpStream, queries: HashMap<&str, &str>) {
92     let chip_create_params = chip::CreateParams {
93         kind: ChipKind::BLUETOOTH,
94         address: queries.get("address").unwrap_or(&"").to_string(),
95         name: Some(format!("websocket-{}", stream.peer_addr().unwrap())),
96         manufacturer: "Google".to_string(),
97         product_name: "Google".to_string(),
98         bt_properties: None,
99     };
100     #[cfg(not(test))]
101     let wireless_create_params =
102         wireless::CreateParam::Bluetooth(wireless::bluetooth::CreateParams {
103             address: chip_create_params.address.clone(),
104             bt_properties: None,
105         });
106     #[cfg(test)]
107     let wireless_create_params = wireless::CreateParam::Mock(wireless::mocked::CreateParams {
108         chip_kind: ChipKind::BLUETOOTH,
109     });
110     // Add Chip
111     let result = match add_chip(
112         &stream.peer_addr().unwrap().port().to_string(),
113         queries
114             .get("name")
115             .unwrap_or(&format!("websocket-device-{}", stream.peer_addr().unwrap()).as_str()),
116         &chip_create_params,
117         &wireless_create_params,
118     ) {
119         Ok(chip_result) => chip_result,
120         Err(err) => {
121             warn!("{err}");
122             return;
123         }
124     };
125 
126     // Create websocket_writer to handle packet responses, write pong or close messages
127     let websocket_writer = Arc::new(Mutex::new(WebSocket::from_raw_socket(
128         stream.try_clone().unwrap(),
129         Role::Server,
130         None,
131     )));
132     // Websocket reader
133     let mut websocket_reader = WebSocket::from_raw_socket(stream, Role::Server, None);
134 
135     // Sending cloned websocket into packet dispatcher
136     register_transport(
137         result.chip_id,
138         Box::new(WebSocketTransport { websocket_writer: websocket_writer.clone() }),
139     );
140 
141     // Running Websocket server
142     loop {
143         let packet_msg =
144             match websocket_reader.read().map_err(|_| "Failed to read Websocket message") {
145                 Ok(message) => message,
146                 Err(err) => {
147                     error!("{err}");
148                     break;
149                 }
150             };
151         if packet_msg.is_binary() {
152             let mut cursor = Cursor::new(packet_msg.into_data());
153             match h4::read_h4_packet(&mut cursor) {
154                 Ok(packet) => {
155                     wireless::handle_request(result.chip_id, &packet.payload, packet.h4_type);
156                 }
157                 Err(error) => {
158                     error!(
159                         "netsimd: end websocket reader {}: {:?}",
160                         websocket_reader.get_ref().peer_addr().unwrap(),
161                         error
162                     );
163                     break;
164                 }
165             }
166         } else if packet_msg.is_ping() {
167             if let Err(err) = websocket_writer
168                 .lock()
169                 .expect("Failed to acquire lock on WebSocket")
170                 .send(Message::Pong(packet_msg.into_data()))
171             {
172                 error!("{err}");
173             }
174         } else if packet_msg.is_close() {
175             if let Message::Close(close_frame) = packet_msg {
176                 if let Err(err) = websocket_writer
177                     .lock()
178                     .expect("Failed to acquire lock on WebSocket")
179                     .close(close_frame)
180                     .map_err(|_| "Failed to close Websocket")
181                 {
182                     error!("{err}");
183                 }
184             }
185             break;
186         }
187     }
188 
189     // unregister before remove_chip because facade may re-use facade_id
190     // on an intertwining create_chip and the unregister here might remove
191     // the recently added chip creating a disconnected transport.
192     unregister_transport(result.chip_id);
193 
194     if let Err(err) = remove_chip(result.device_id, result.chip_id) {
195         warn!("{err}");
196     };
197     info!("Removed chip: device_id: {}, chip_id: {}", result.device_id, result.chip_id);
198 }
199