1 //
2 // Copyright 2017 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 
17 #include "desktop/test_environment.h"
18 
19 #include <google/protobuf/text_format.h>
20 
21 #include <chrono>
22 #include <filesystem>
23 #include <fstream>
24 #include <functional>
25 #include <future>
26 #include <ios>
27 #include <memory>
28 #include <string>
29 #include <utility>
30 #include <vector>
31 
32 #include "hci/pcap_filter.h"
33 #include "log.h"
34 #include "model/controller/controller_properties.h"
35 #include "model/devices/baseband_sniffer.h"
36 #include "model/devices/device.h"
37 #include "model/devices/hci_device.h"
38 #include "model/devices/link_layer_socket_device.h"
39 #include "model/hci/hci_sniffer.h"
40 #include "model/hci/hci_socket_transport.h"
41 #include "model/setup/async_manager.h"
42 #include "model/setup/test_channel_transport.h"
43 #include "net/async_data_channel.h"
44 #include "net/async_data_channel_connector.h"
45 #include "phy.h"
46 #include "rootcanal/configuration.pb.h"
47 
48 namespace rootcanal {
49 
50 using rootcanal::AsyncTaskId;
51 using rootcanal::BaseBandSniffer;
52 using rootcanal::HciDevice;
53 using rootcanal::HciSniffer;
54 using rootcanal::HciSocketTransport;
55 using rootcanal::LinkLayerSocketDevice;
56 using rootcanal::TaskCallback;
57 
TestEnvironment(std::function<std::shared_ptr<AsyncDataChannelServer> (AsyncManager *,int)> open_server,std::function<std::shared_ptr<AsyncDataChannelConnector> (AsyncManager *)> open_connector,int test_port,int hci_port,int link_port,int link_ble_port,const std::string & config_str,bool enable_hci_sniffer,bool enable_baseband_sniffer,bool enable_pcap_filter,bool disable_address_reuse)58 TestEnvironment::TestEnvironment(
59     std::function<std::shared_ptr<AsyncDataChannelServer>(AsyncManager*, int)>
60         open_server,
61     std::function<std::shared_ptr<AsyncDataChannelConnector>(AsyncManager*)>
62         open_connector,
63     int test_port, int hci_port, int link_port, int link_ble_port,
64     const std::string& config_str,
65     bool enable_hci_sniffer, bool enable_baseband_sniffer,
66     bool enable_pcap_filter, bool disable_address_reuse)
67     : enable_hci_sniffer_(enable_hci_sniffer),
68       enable_baseband_sniffer_(enable_baseband_sniffer),
69       enable_pcap_filter_(enable_pcap_filter) {
70   test_socket_server_ = open_server(&async_manager_, test_port);
71   link_socket_server_ = open_server(&async_manager_, link_port);
72   link_ble_socket_server_ = open_server(&async_manager_, link_ble_port);
73   connector_ = open_connector(&async_manager_);
74   test_model_.SetReuseDeviceAddresses(!disable_address_reuse);
75 
76   // Get a user ID for tasks scheduled within the test environment.
77   socket_user_id_ = async_manager_.GetNextUserId();
78 
79   rootcanal::configuration::Configuration* config =
80       new rootcanal::configuration::Configuration();
81   if (!google::protobuf::TextFormat::ParseFromString(config_str, config) ||
82       config->tcp_server_size() == 0) {
83     // Default configuration with default hci port if the input
84     // configuration cannot be used.
85     SetUpHciServer(open_server, hci_port, rootcanal::ControllerProperties());
86   } else {
87     // Open an HCI server for all configurations requested by
88     // the caller.
89     int num_controllers = config->tcp_server_size();
90     for (int index = 0; index < num_controllers; index++) {
91       rootcanal::configuration::TcpServer const& tcp_server =
92           config->tcp_server(index);
93       SetUpHciServer(open_server, tcp_server.tcp_port(),
94                      rootcanal::ControllerProperties(tcp_server.configuration()));
95     }
96   }
97 }
98 
99 // Open an HCI server listening on the port `tcp_port`. Established connections
100 // are bound to a controller with the specified `properties`.
SetUpHciServer(std::function<std::shared_ptr<AsyncDataChannelServer> (AsyncManager *,int)> open_server,int tcp_port,rootcanal::ControllerProperties properties)101 void TestEnvironment::SetUpHciServer(
102     std::function<std::shared_ptr<AsyncDataChannelServer>(AsyncManager*, int)>
103         open_server,
104     int tcp_port, rootcanal::ControllerProperties properties) {
105   INFO("Opening an HCI with port {}", tcp_port);
106 
107   std::shared_ptr<AsyncDataChannelServer> server =
108       open_server(&async_manager_, tcp_port);
109   server->SetOnConnectCallback([this, properties = std::move(properties)](
110                                    std::shared_ptr<AsyncDataChannel> socket,
111                                    AsyncDataChannelServer* server) {
112     // AddHciConnection needs to be executed in task thread to
113     // prevent data races on test model.
114     async_manager_.ExecAsync(socket_user_id_, std::chrono::milliseconds(0),
115                              [=]() {
116       auto transport = HciSocketTransport::Create(socket);
117       if (enable_hci_sniffer_) {
118         transport = HciSniffer::Create(transport);
119       }
120       auto device = HciDevice::Create(transport, properties);
121       auto device_id = test_model_.AddHciConnection(device);
122 
123       if (enable_hci_sniffer_) {
124         auto filename = "rootcanal_" + std::to_string(device_id) + "_" +
125                         device->GetAddress().ToString() + ".pcap";
126         for (auto i = 0; std::filesystem::exists(filename); i++) {
127           filename = "rootcanal_" + std::to_string(device_id) + "_" +
128                      device->GetAddress().ToString() + "_" + std::to_string(i) +
129                      ".pcap";
130         }
131         auto file = std::make_shared<std::ofstream>(filename, std::ios::binary);
132         auto sniffer = std::static_pointer_cast<HciSniffer>(transport);
133 
134         // Add PCAP output stream.
135         sniffer->SetOutputStream(file);
136 
137         // Add a PCAP filter if the option is enabled.
138         // TODO: ideally the filter should be shared between all transport
139         // instances to use the same user information remapping between traces.
140         if (enable_pcap_filter_) {
141           sniffer->SetPcapFilter(std::make_shared<rootcanal::PcapFilter>());
142         }
143       }
144     });
145 
146     server->StartListening();
147   });
148   hci_socket_servers_.emplace_back(std::move(server));
149 }
150 
initialize(std::promise<void> barrier)151 void TestEnvironment::initialize(std::promise<void> barrier) {
152   INFO("Initialized barrier");
153 
154   barrier_ = std::move(barrier);
155 
156   test_channel_transport_.RegisterCommandHandler(
157       [this](const std::string& name, const std::vector<std::string>& args) {
158         async_manager_.ExecAsync(socket_user_id_, std::chrono::milliseconds(0),
159                                  [this, name, args]() {
160                                    if (name == "END_SIMULATION") {
161                                      barrier_.set_value();
162                                    } else {
163                                      test_channel_.HandleCommand(name, args);
164                                    }
165                                  });
166       });
167 
168   SetUpTestChannel();
169   SetUpLinkLayerServer();
170   SetUpLinkBleLayerServer();
171 
172   for (auto& server : hci_socket_servers_) {
173     server->StartListening();
174   }
175 
176   if (enable_baseband_sniffer_) {
177     std::string filename = "baseband.pcap";
178     for (auto i = 0; std::filesystem::exists(filename); i++) {
179       filename = "baseband_" + std::to_string(i) + ".pcap";
180     }
181 
182     test_model_.AddLinkLayerConnection(BaseBandSniffer::Create(filename),
183                                        Phy::Type::BR_EDR);
184   }
185 
186   INFO("{}: Finished", __func__);
187 }
188 
close()189 void TestEnvironment::close() {
190   INFO("{}", __func__);
191   test_model_.Reset();
192 }
193 
SetUpLinkBleLayerServer()194 void TestEnvironment::SetUpLinkBleLayerServer() {
195   link_ble_socket_server_->SetOnConnectCallback(
196       [this](std::shared_ptr<AsyncDataChannel> socket,
197              AsyncDataChannelServer* srv) {
198         auto phy_type = Phy::Type::LOW_ENERGY;
199         test_model_.AddLinkLayerConnection(
200             LinkLayerSocketDevice::Create(socket, phy_type), phy_type);
201         srv->StartListening();
202       });
203   link_ble_socket_server_->StartListening();
204 }
205 
SetUpLinkLayerServer()206 void TestEnvironment::SetUpLinkLayerServer() {
207   link_socket_server_->SetOnConnectCallback(
208       [this](std::shared_ptr<AsyncDataChannel> socket,
209              AsyncDataChannelServer* srv) {
210         auto phy_type = Phy::Type::BR_EDR;
211         test_model_.AddLinkLayerConnection(
212             LinkLayerSocketDevice::Create(socket, phy_type), phy_type);
213         srv->StartListening();
214       });
215   link_socket_server_->StartListening();
216 }
217 
ConnectToRemoteServer(const std::string & server,int port,Phy::Type phy_type)218 std::shared_ptr<Device> TestEnvironment::ConnectToRemoteServer(
219     const std::string& server, int port, Phy::Type phy_type) {
220   auto socket = connector_->ConnectToRemoteServer(server, port);
221   if (!socket->Connected()) {
222     return nullptr;
223   }
224   return LinkLayerSocketDevice::Create(socket, phy_type);
225 }
226 
SetUpTestChannel()227 void TestEnvironment::SetUpTestChannel() {
228   bool transport_configured = test_channel_transport_.SetUp(
229       test_socket_server_, [this](std::shared_ptr<AsyncDataChannel> conn_fd,
230                                   AsyncDataChannelServer* server) {
231         INFO("Test channel connection accepted.");
232         server->StartListening();
233         if (test_channel_open_) {
234           WARNING("Only one connection at a time is supported");
235           rootcanal::TestChannelTransport::SendResponse(
236               conn_fd, "The connection is broken");
237           return false;
238         }
239         test_channel_open_ = true;
240         test_channel_.RegisterSendResponse(
241             [conn_fd](const std::string& response) {
242               rootcanal::TestChannelTransport::SendResponse(conn_fd, response);
243             });
244 
245         conn_fd->WatchForNonBlockingRead([this](AsyncDataChannel* conn_fd) {
246           test_channel_transport_.OnCommandReady(
247               conn_fd, [this]() { test_channel_open_ = false; });
248         });
249         return false;
250       });
251 
252   test_channel_.AddPhy({"BR_EDR"});
253   test_channel_.AddPhy({"LOW_ENERGY"});
254   test_channel_.AddDevice({"beacon", "be:ac:01:55:00:01", "1000"});
255   test_channel_.AddDeviceToPhy({"0", "1"});
256   test_channel_.AddDevice({"beacon", "be:ac:01:55:00:02", "1000"});
257   test_channel_.AddDeviceToPhy({"1", "1"});
258   test_channel_.SetTimerPeriod({"5"});
259   test_channel_.StartTimer({});
260 
261   if (!transport_configured) {
262     ERROR("Test channel SetUp failed.");
263     return;
264   }
265 
266   INFO("Test channel SetUp() successful");
267 }
268 
269 }  // namespace rootcanal
270