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)> open_server,
60 std::function<std::shared_ptr<AsyncDataChannelConnector>(AsyncManager*)> open_connector,
61 int test_port, int hci_port, int link_port, int link_ble_port,
62 const std::string& config_str, bool enable_hci_sniffer, bool enable_baseband_sniffer,
63 bool enable_pcap_filter, bool disable_address_reuse)
64 : enable_hci_sniffer_(enable_hci_sniffer),
65 enable_baseband_sniffer_(enable_baseband_sniffer),
66 enable_pcap_filter_(enable_pcap_filter) {
67 test_socket_server_ = open_server(&async_manager_, test_port);
68 link_socket_server_ = open_server(&async_manager_, link_port);
69 link_ble_socket_server_ = open_server(&async_manager_, link_ble_port);
70 connector_ = open_connector(&async_manager_);
71 test_model_.SetReuseDeviceAddresses(!disable_address_reuse);
72
73 // Get a user ID for tasks scheduled within the test environment.
74 socket_user_id_ = async_manager_.GetNextUserId();
75
76 rootcanal::configuration::Configuration* config = new rootcanal::configuration::Configuration();
77 if (!google::protobuf::TextFormat::ParseFromString(config_str, config) ||
78 config->tcp_server_size() == 0) {
79 // Default configuration with default hci port if the input
80 // configuration cannot be used.
81 SetUpHciServer(open_server, hci_port, rootcanal::ControllerProperties());
82 } else {
83 // Open an HCI server for all configurations requested by
84 // the caller.
85 int num_controllers = config->tcp_server_size();
86 for (int index = 0; index < num_controllers; index++) {
87 rootcanal::configuration::TcpServer const& tcp_server = config->tcp_server(index);
88 SetUpHciServer(open_server, tcp_server.tcp_port(),
89 rootcanal::ControllerProperties(tcp_server.configuration()));
90 }
91 }
92 }
93
94 // Open an HCI server listening on the port `tcp_port`. Established connections
95 // 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)96 void TestEnvironment::SetUpHciServer(
97 std::function<std::shared_ptr<AsyncDataChannelServer>(AsyncManager*, int)> open_server,
98 int tcp_port, rootcanal::ControllerProperties properties) {
99 INFO("Opening an HCI with port {}", tcp_port);
100
101 std::shared_ptr<AsyncDataChannelServer> server = open_server(&async_manager_, tcp_port);
102 server->SetOnConnectCallback(
103 [this, properties = std::move(properties)](std::shared_ptr<AsyncDataChannel> socket,
104 AsyncDataChannelServer* server) {
105 // AddHciConnection needs to be executed in task thread to
106 // prevent data races on test model.
107 async_manager_.ExecAsync(socket_user_id_, std::chrono::milliseconds(0), [=, this]() {
108 auto transport = HciSocketTransport::Create(socket);
109 if (enable_hci_sniffer_) {
110 transport = HciSniffer::Create(transport);
111 }
112 auto device = HciDevice::Create(transport, properties);
113 auto device_id = test_model_.AddHciConnection(device);
114
115 if (enable_hci_sniffer_) {
116 auto filename = "rootcanal_" + std::to_string(device_id) + "_" +
117 device->GetAddress().ToString() + ".pcap";
118 for (auto i = 0; std::filesystem::exists(filename); i++) {
119 filename = "rootcanal_" + std::to_string(device_id) + "_" +
120 device->GetAddress().ToString() + "_" + std::to_string(i) + ".pcap";
121 }
122 auto file = std::make_shared<std::ofstream>(filename, std::ios::binary);
123 auto sniffer = std::static_pointer_cast<HciSniffer>(transport);
124
125 // Add PCAP output stream.
126 sniffer->SetOutputStream(file);
127
128 // Add a PCAP filter if the option is enabled.
129 // TODO: ideally the filter should be shared between all transport
130 // instances to use the same user information remapping between traces.
131 if (enable_pcap_filter_) {
132 sniffer->SetPcapFilter(std::make_shared<rootcanal::PcapFilter>());
133 }
134 }
135 });
136
137 server->StartListening();
138 });
139 hci_socket_servers_.emplace_back(std::move(server));
140 }
141
initialize(std::promise<void> barrier)142 void TestEnvironment::initialize(std::promise<void> barrier) {
143 INFO("Initialized barrier");
144
145 barrier_ = std::move(barrier);
146
147 test_channel_transport_.RegisterCommandHandler([this](const std::string& name,
148 const std::vector<std::string>& args) {
149 async_manager_.ExecAsync(socket_user_id_, std::chrono::milliseconds(0), [this, name, args]() {
150 if (name == "END_SIMULATION") {
151 barrier_.set_value();
152 } else {
153 test_channel_.HandleCommand(name, args);
154 }
155 });
156 });
157
158 SetUpTestChannel();
159 SetUpLinkLayerServer();
160 SetUpLinkBleLayerServer();
161
162 for (auto& server : hci_socket_servers_) {
163 server->StartListening();
164 }
165
166 if (enable_baseband_sniffer_) {
167 std::string filename = "baseband.pcap";
168 for (auto i = 0; std::filesystem::exists(filename); i++) {
169 filename = "baseband_" + std::to_string(i) + ".pcap";
170 }
171
172 test_model_.AddLinkLayerConnection(BaseBandSniffer::Create(filename), Phy::Type::BR_EDR);
173 }
174
175 INFO("{}: Finished", __func__);
176 }
177
close()178 void TestEnvironment::close() {
179 INFO("{}", __func__);
180 test_model_.Reset();
181 }
182
SetUpLinkBleLayerServer()183 void TestEnvironment::SetUpLinkBleLayerServer() {
184 link_ble_socket_server_->SetOnConnectCallback([this](std::shared_ptr<AsyncDataChannel> socket,
185 AsyncDataChannelServer* srv) {
186 auto phy_type = Phy::Type::LOW_ENERGY;
187 test_model_.AddLinkLayerConnection(LinkLayerSocketDevice::Create(socket, phy_type), phy_type);
188 srv->StartListening();
189 });
190 link_ble_socket_server_->StartListening();
191 }
192
SetUpLinkLayerServer()193 void TestEnvironment::SetUpLinkLayerServer() {
194 link_socket_server_->SetOnConnectCallback([this](std::shared_ptr<AsyncDataChannel> socket,
195 AsyncDataChannelServer* srv) {
196 auto phy_type = Phy::Type::BR_EDR;
197 test_model_.AddLinkLayerConnection(LinkLayerSocketDevice::Create(socket, phy_type), phy_type);
198 srv->StartListening();
199 });
200 link_socket_server_->StartListening();
201 }
202
ConnectToRemoteServer(const std::string & server,int port,Phy::Type phy_type)203 std::shared_ptr<Device> TestEnvironment::ConnectToRemoteServer(const std::string& server, int port,
204 Phy::Type phy_type) {
205 auto socket = connector_->ConnectToRemoteServer(server, port);
206 if (!socket->Connected()) {
207 return nullptr;
208 }
209 return LinkLayerSocketDevice::Create(socket, phy_type);
210 }
211
SetUpTestChannel()212 void TestEnvironment::SetUpTestChannel() {
213 bool transport_configured = test_channel_transport_.SetUp(
214 test_socket_server_,
215 [this](std::shared_ptr<AsyncDataChannel> conn_fd, AsyncDataChannelServer* server) {
216 INFO("Test channel connection accepted.");
217 server->StartListening();
218 if (test_channel_open_) {
219 WARNING("Only one connection at a time is supported");
220 rootcanal::TestChannelTransport::SendResponse(conn_fd, "The connection is broken");
221 return false;
222 }
223 test_channel_open_ = true;
224 test_channel_.RegisterSendResponse([conn_fd](const std::string& response) {
225 rootcanal::TestChannelTransport::SendResponse(conn_fd, response);
226 });
227
228 conn_fd->WatchForNonBlockingRead([this](AsyncDataChannel* conn_fd) {
229 test_channel_transport_.OnCommandReady(conn_fd,
230 [this]() { test_channel_open_ = false; });
231 });
232 return false;
233 });
234
235 test_channel_.AddPhy({"BR_EDR"});
236 test_channel_.AddPhy({"LOW_ENERGY"});
237 test_channel_.AddDevice({"beacon", "be:ac:01:55:00:01", "1000"});
238 test_channel_.AddDeviceToPhy({"0", "1"});
239 test_channel_.AddDevice({"beacon", "be:ac:01:55:00:02", "1000"});
240 test_channel_.AddDeviceToPhy({"1", "1"});
241 test_channel_.SetTimerPeriod({"5"});
242 test_channel_.StartTimer({});
243
244 if (!transport_configured) {
245 ERROR("Test channel SetUp failed.");
246 return;
247 }
248
249 INFO("Test channel SetUp() successful");
250 }
251
252 } // namespace rootcanal
253