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 #pragma once 16 #include <lib/fit/function.h> 17 18 #include <list> 19 20 #include "pw_bluetooth_sapphire/internal/host/common/identifier.h" 21 #include "pw_bluetooth_sapphire/internal/host/common/inspectable.h" 22 #include "pw_bluetooth_sapphire/internal/host/gap/peer.h" 23 #include "pw_bluetooth_sapphire/internal/host/hci-spec/protocol.h" 24 #include "pw_bluetooth_sapphire/internal/host/transport/error.h" 25 26 namespace bt::gap { 27 28 class BrEdrConnection; 29 30 // A |BrEdrConnectionRequest| represents a request for the GAP to connect to a 31 // given |DeviceAddress| by one or more clients. BrEdrConnectionManager is 32 // responsible for tracking ConnectionRequests and passing them to the Connector 33 // when ready. 34 // 35 // There is at most One BrEdrConnectionRequest per address at any given time; if 36 // multiple clients wish to connect, they each append a callback to the list in 37 // the ConnectionRequest for the device they are interested in. 38 // 39 // If a remote peer makes an incoming request for a connection, we track that 40 // here also - whether an incoming request is pending is indicated by 41 // HasIncoming() 42 class BrEdrConnectionRequest final { 43 public: 44 using OnComplete = fit::function<void(hci::Result<>, BrEdrConnection*)>; 45 using RefFactory = fit::function<BrEdrConnection*()>; 46 47 // Construct without a callback. Can be used for incoming only requests 48 BrEdrConnectionRequest(pw::async::Dispatcher& pw_dispatcher, 49 const DeviceAddress& addr, 50 PeerId peer_id, 51 Peer::InitializingConnectionToken token); 52 53 BrEdrConnectionRequest(pw::async::Dispatcher& pw_dispatcher, 54 const DeviceAddress& addr, 55 PeerId peer_id, 56 Peer::InitializingConnectionToken token, 57 OnComplete&& callback); 58 59 BrEdrConnectionRequest(BrEdrConnectionRequest&&) = default; 60 61 void RecordHciCreateConnectionAttempt(); 62 bool ShouldRetry(hci::Error failure_mode); 63 AddCallback(OnComplete cb)64 void AddCallback(OnComplete cb) { 65 callbacks_.Mutable()->push_back(std::move(cb)); 66 } 67 68 // Notifies all elements in |callbacks| with |status| and the result of 69 // |generate_ref|. Called by the appropriate manager once a connection request 70 // has completed, successfully or otherwise 71 void NotifyCallbacks(hci::Result<> status, const RefFactory& generate_ref); 72 BeginIncoming()73 void BeginIncoming() { has_incoming_.Set(true); } CompleteIncoming()74 void CompleteIncoming() { has_incoming_.Set(false); } HasIncoming()75 bool HasIncoming() const { return *has_incoming_; } AwaitingOutgoing()76 bool AwaitingOutgoing() { return !callbacks_->empty(); } 77 78 // Attach request inspect node as a child of |parent| named |name|. 79 void AttachInspect(inspect::Node& parent, std::string name); 80 address()81 DeviceAddress address() const { return address_; } 82 83 // If a role change occurs while this request is still pending, set it here so 84 // that the correct role is used when connection establishment completes. set_role_change(pw::bluetooth::emboss::ConnectionRole role)85 void set_role_change(pw::bluetooth::emboss::ConnectionRole role) { 86 role_change_ = role; 87 } 88 89 // If the default role of the requested connection is changed during 90 // connection establishment, the new role will be returned. role_change()91 const std::optional<pw::bluetooth::emboss::ConnectionRole>& role_change() 92 const { 93 return role_change_; 94 } 95 take_peer_init_token()96 Peer::InitializingConnectionToken take_peer_init_token() { 97 BT_ASSERT(peer_init_conn_token_); 98 return std::exchange(peer_init_conn_token_, std::nullopt).value(); 99 } 100 101 private: 102 PeerId peer_id_; 103 DeviceAddress address_; 104 UintInspectable<std::list<OnComplete>> callbacks_; 105 BoolInspectable<bool> has_incoming_{false}; 106 std::optional<pw::bluetooth::emboss::ConnectionRole> role_change_; 107 // Used to determine whether an outbound connection request should be retried. 108 // If empty, no HCI Create Connection Requests associated with this object 109 // have been made, otherwise stores the time at which the first HCI request 110 // associated with this object was made. 111 IntInspectable<std::optional<pw::chrono::SystemClock::time_point>> 112 first_create_connection_req_made_{ 113 std::nullopt, 114 [](auto& t) { return t ? t->time_since_epoch().count() : -1; }}; 115 116 inspect::StringProperty peer_id_property_; 117 inspect::Node inspect_node_; 118 119 std::optional<Peer::InitializingConnectionToken> peer_init_conn_token_; 120 121 pw::async::Dispatcher& dispatcher_; 122 123 BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(BrEdrConnectionRequest); 124 }; 125 126 } // namespace bt::gap 127