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 crate::devices::chip::ChipIdentifier;
16 use crate::ffi::ffi_transport::handle_grpc_response;
17 use crate::wireless::packet::{register_transport, unregister_transport, Response};
18 use bytes::Bytes;
19 use futures_executor::block_on;
20 use futures_util::SinkExt as _;
21 use grpcio::WriteFlags;
22 use netsim_proto::hci_packet::{hcipacket::PacketType, HCIPacket};
23 use netsim_proto::packet_streamer::PacketResponse;
24 use protobuf::Enum;
25 use protobuf::EnumOrUnknown;
26 
27 /// Grpc transport.
28 ///
29 /// This module provides a wrapper around the C++ Grpc implementation. It
30 /// provides a higher-level API that is easier to use from Rust.
31 
32 struct GrpcTransport {
33     chip_id: u32,
34 }
35 
36 impl Response for GrpcTransport {
response(&mut self, packet: Bytes, packet_type: u8)37     fn response(&mut self, packet: Bytes, packet_type: u8) {
38         handle_grpc_response(self.chip_id, &packet.to_vec(), packet_type)
39     }
40 }
41 
42 // for grpc server in C++
register_grpc_transport(chip_id: u32)43 pub fn register_grpc_transport(chip_id: u32) {
44     register_transport(ChipIdentifier(chip_id), Box::new(GrpcTransport { chip_id }));
45 }
46 
47 // for grpc server in C++
unregister_grpc_transport(chip_id: u32)48 pub fn unregister_grpc_transport(chip_id: u32) {
49     unregister_transport(ChipIdentifier(chip_id));
50 }
51 
52 /// Rust grpc transport.s
53 pub struct RustGrpcTransport {
54     pub sink: grpcio::DuplexSink<PacketResponse>,
55 }
56 
57 impl Response for RustGrpcTransport {
response(&mut self, packet: Bytes, packet_type: u8)58     fn response(&mut self, packet: Bytes, packet_type: u8) {
59         let mut response = PacketResponse::new();
60         if packet_type != (PacketType::HCI_PACKET_UNSPECIFIED.value() as u8) {
61             let hci_packet = HCIPacket {
62                 packet_type: EnumOrUnknown::from_i32(packet_type as i32),
63                 packet: packet.to_vec(),
64                 ..Default::default()
65             };
66             response.set_hci_packet(hci_packet);
67         } else {
68             response.set_packet(packet.to_vec());
69         }
70         block_on(async {
71             let _ = self.sink.send((response, WriteFlags::default())).await;
72         });
73     }
74 }
75