| // Copyright 2021 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "bredr_connection_request.h" |
| |
| #include "lib/async/cpp/time.h" |
| #include "lib/async/default.h" |
| |
| namespace bt::gap { |
| |
| namespace { |
| |
| const char* const kInspectHasIncomingPropertyName = "has_incoming"; |
| const char* const kInspectCallbacksPropertyName = "callbacks"; |
| const char* const kInspectFirstCreateConnectionReqMadeName = |
| "first_create_connection_request_timestamp"; |
| const char* const kInspectPeerIdPropertyName = "peer_id"; |
| constexpr zx::duration kRetryWindowAfterFirstCreateConn = zx::sec(30); |
| |
| } // namespace |
| |
| BrEdrConnectionRequest::BrEdrConnectionRequest(const DeviceAddress& addr, PeerId peer_id, |
| Peer::InitializingConnectionToken token) |
| : peer_id_(peer_id), |
| address_(addr), |
| callbacks_(/*convert=*/[](auto& c) { return c.size(); }), |
| has_incoming_(false), |
| first_create_connection_req_made_( |
| std::nullopt, [](const std::optional<zx::time>& t) { return t ? t->get() : -1; }), |
| peer_init_conn_token_(std::move(token)) {} |
| |
| BrEdrConnectionRequest::BrEdrConnectionRequest(const DeviceAddress& addr, PeerId peer_id, |
| Peer::InitializingConnectionToken token, |
| OnComplete&& callback) |
| : BrEdrConnectionRequest(addr, peer_id, std::move(token)) { |
| callbacks_.Mutable()->push_back(std::move(callback)); |
| } |
| |
| void BrEdrConnectionRequest::NotifyCallbacks(hci::Result<> status, const RefFactory& generate_ref) { |
| // Clear token before notifying callbacks so that connection state change is reflected in |
| // callbacks. |
| peer_init_conn_token_.reset(); |
| |
| // If this request has been moved from, |callbacks_| may be empty. |
| for (const auto& callback : *callbacks_) { |
| callback(status, generate_ref()); |
| } |
| } |
| |
| void BrEdrConnectionRequest::AttachInspect(inspect::Node& parent, std::string name) { |
| inspect_node_ = parent.CreateChild(name); |
| has_incoming_.AttachInspect(inspect_node_, kInspectHasIncomingPropertyName); |
| callbacks_.AttachInspect(inspect_node_, kInspectCallbacksPropertyName); |
| first_create_connection_req_made_.AttachInspect(inspect_node_, |
| kInspectFirstCreateConnectionReqMadeName); |
| peer_id_property_ = inspect_node_.CreateString(kInspectPeerIdPropertyName, peer_id_.ToString()); |
| } |
| |
| void BrEdrConnectionRequest::RecordHciCreateConnectionAttempt() { |
| if (!first_create_connection_req_made_.value()) { |
| first_create_connection_req_made_.Set(async::Now(async_get_default_dispatcher())); |
| } |
| } |
| |
| bool BrEdrConnectionRequest::ShouldRetry(hci::Error failure_mode) { |
| zx::time now = async::Now(async_get_default_dispatcher()); |
| std::optional<zx::time> first_create_conn_req_made = first_create_connection_req_made_.value(); |
| return failure_mode.is(hci_spec::kPageTimeout) && first_create_conn_req_made.has_value() && |
| now - *first_create_conn_req_made < kRetryWindowAfterFirstCreateConn; |
| } |
| } // namespace bt::gap |