• 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 #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