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