• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2023 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // 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, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #include "pw_bluetooth_sapphire/internal/host/gap/bredr_connection_request.h"
16 
17 namespace bt::gap {
18 
19 namespace {
20 
21 const char* const kInspectHasIncomingPropertyName = "has_incoming";
22 const char* const kInspectCallbacksPropertyName = "callbacks";
23 const char* const kInspectFirstCreateConnectionReqMadeName =
24     "first_create_connection_request_timestamp";
25 const char* const kInspectPeerIdPropertyName = "peer_id";
26 constexpr pw::chrono::SystemClock::duration kRetryWindowAfterFirstCreateConn =
27     std::chrono::seconds(30);
28 
29 }  // namespace
30 
BrEdrConnectionRequest(pw::async::Dispatcher & pw_dispatcher,const DeviceAddress & addr,PeerId peer_id,Peer::InitializingConnectionToken token)31 BrEdrConnectionRequest::BrEdrConnectionRequest(
32     pw::async::Dispatcher& pw_dispatcher,
33     const DeviceAddress& addr,
34     PeerId peer_id,
35     Peer::InitializingConnectionToken token)
36     : peer_id_(peer_id),
37       address_(addr),
38       callbacks_(/*convert=*/[](auto& c) { return c.size(); }),
39       peer_init_conn_token_(std::move(token)),
40       dispatcher_(pw_dispatcher) {}
41 
BrEdrConnectionRequest(pw::async::Dispatcher & pw_dispatcher,const DeviceAddress & addr,PeerId peer_id,Peer::InitializingConnectionToken token,OnComplete && callback)42 BrEdrConnectionRequest::BrEdrConnectionRequest(
43     pw::async::Dispatcher& pw_dispatcher,
44     const DeviceAddress& addr,
45     PeerId peer_id,
46     Peer::InitializingConnectionToken token,
47     OnComplete&& callback)
48     : BrEdrConnectionRequest(pw_dispatcher, addr, peer_id, std::move(token)) {
49   callbacks_.Mutable()->push_back(std::move(callback));
50 }
51 
NotifyCallbacks(hci::Result<> status,const RefFactory & generate_ref)52 void BrEdrConnectionRequest::NotifyCallbacks(hci::Result<> status,
53                                              const RefFactory& generate_ref) {
54   // Clear token before notifying callbacks so that connection state change is
55   // reflected in callbacks.
56   peer_init_conn_token_.reset();
57 
58   // If this request has been moved from, |callbacks_| may be empty.
59   for (const auto& callback : *callbacks_) {
60     callback(status, generate_ref());
61   }
62 }
63 
AttachInspect(inspect::Node & parent,std::string name)64 void BrEdrConnectionRequest::AttachInspect(inspect::Node& parent,
65                                            std::string name) {
66   inspect_node_ = parent.CreateChild(name);
67   has_incoming_.AttachInspect(inspect_node_, kInspectHasIncomingPropertyName);
68   callbacks_.AttachInspect(inspect_node_, kInspectCallbacksPropertyName);
69   first_create_connection_req_made_.AttachInspect(
70       inspect_node_, kInspectFirstCreateConnectionReqMadeName);
71   peer_id_property_ = inspect_node_.CreateString(kInspectPeerIdPropertyName,
72                                                  peer_id_.ToString());
73 }
74 
RecordHciCreateConnectionAttempt()75 void BrEdrConnectionRequest::RecordHciCreateConnectionAttempt() {
76   if (!first_create_connection_req_made_.value()) {
77     first_create_connection_req_made_.Set(dispatcher_.now());
78   }
79 }
80 
ShouldRetry(hci::Error failure_mode)81 bool BrEdrConnectionRequest::ShouldRetry(hci::Error failure_mode) {
82   pw::chrono::SystemClock::time_point now = dispatcher_.now();
83   std::optional<pw::chrono::SystemClock::time_point>
84       first_create_conn_req_made = first_create_connection_req_made_.value();
85   return failure_mode.is(pw::bluetooth::emboss::StatusCode::PAGE_TIMEOUT) &&
86          first_create_conn_req_made.has_value() &&
87          now - *first_create_conn_req_made < kRetryWindowAfterFirstCreateConn;
88 }
89 }  // namespace bt::gap
90