summaryrefslogtreecommitdiff
path: root/chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.h
blob: c77c894ab536855710410e57c3b5ac1a09e01f89 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_CRYPTAUTH_BLE_BLUETOOTH_LOW_ENERGY_WEAVE_CLIENT_CONNECTION_H_
#define COMPONENTS_CRYPTAUTH_BLE_BLUETOOTH_LOW_ENERGY_WEAVE_CLIENT_CONNECTION_H_

#include <stddef.h>
#include <stdint.h>

#include <map>
#include <memory>
#include <queue>
#include <string>

#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "components/cryptauth/ble/bluetooth_low_energy_characteristics_finder.h"
#include "components/cryptauth/ble/bluetooth_low_energy_weave_packet_generator.h"
#include "components/cryptauth/ble/bluetooth_low_energy_weave_packet_receiver.h"
#include "components/cryptauth/ble/fake_wire_message.h"
#include "components/cryptauth/ble/remote_attribute.h"
#include "components/cryptauth/bluetooth_throttler.h"
#include "components/cryptauth/connection.h"
#include "device/bluetooth/bluetooth_adapter.h"
#include "device/bluetooth/bluetooth_device.h"
#include "device/bluetooth/bluetooth_gatt_notify_session.h"
#include "device/bluetooth/bluetooth_remote_gatt_characteristic.h"
#include "device/bluetooth/bluetooth_uuid.h"

namespace base {
class TaskRunner;
}

namespace cryptauth {

namespace weave {

// Creates GATT connection on top of the BLE connection and act as a Client.
// uWeave communication follows the flow:
// Client                           | Server
// ---------------------------------|--------------------------------
// send connection request          |
//                                  | receive connection request
//                                  | send connection response
// receive connection response      |
// opt: send data                   | opt: send data
// receive data                     | receive data
// opt: close connection            | opt: close connection
class BluetoothLowEnergyWeaveClientConnection
    : public Connection,
      public device::BluetoothAdapter::Observer {
 public:
  class Factory {
   public:
    static std::unique_ptr<Connection> NewInstance(
        const RemoteDevice& remote_device,
        const std::string& device_address,
        scoped_refptr<device::BluetoothAdapter> adapter,
        const device::BluetoothUUID remote_service_uuid,
        BluetoothThrottler* bluetooth_throttler);

    // Exposed for testing.
    static void SetInstanceForTesting(std::shared_ptr<Factory> factory);

   protected:
    // Exposed for testing.
    virtual std::unique_ptr<Connection> BuildInstance(
        const RemoteDevice& remote_device,
        const std::string& device_address,
        scoped_refptr<device::BluetoothAdapter> adapter,
        const device::BluetoothUUID remote_service_uuid,
        BluetoothThrottler* bluetooth_throttler);

   private:
    static std::shared_ptr<Factory> factory_instance_;
  };

  // The sub-state of a BluetoothLowEnergyWeaveClientConnection
  // extends the IN_PROGRESS state of Connection::Status.
  enum SubStatus {
    DISCONNECTED,
    WAITING_GATT_CONNECTION,
    WAITING_CHARACTERISTICS,
    CHARACTERISTICS_FOUND,
    WAITING_NOTIFY_SESSION,
    NOTIFY_SESSION_READY,
    WAITING_CONNECTION_RESPONSE,
    CONNECTED,
  };

  // Constructs a Bluetooth low energy connection to the service with
  // |remote_service_| on the |remote_device|. The |adapter| must be already
  // initialized and ready. The GATT connection may alreaady be established and
  // pass through |gatt_connection|. A subsequent call to Connect() must be
  // made.
  BluetoothLowEnergyWeaveClientConnection(
      const RemoteDevice& remote_device,
      const std::string& device_address,
      scoped_refptr<device::BluetoothAdapter> adapter,
      const device::BluetoothUUID remote_service_uuid,
      BluetoothThrottler* bluetooth_throttler);

  ~BluetoothLowEnergyWeaveClientConnection() override;

  // namespace Connection:
  void Connect() override;
  void Disconnect() override;
  std::string GetDeviceAddress() override;

 protected:
  // Exposed for testing.
  // NOTE: This method may indirectly cause this object's destructor to be
  // called. Do not perform any operations that touch the internals of this
  // class after calling this method.
  void DestroyConnection();

  // Exposed for testing.
  SubStatus sub_status() { return sub_status_; }

  // Sets |task_runner_| for testing.
  void SetTaskRunnerForTesting(scoped_refptr<base::TaskRunner> task_runner);

  // Virtual for testing.
  virtual BluetoothLowEnergyCharacteristicsFinder* CreateCharacteristicsFinder(
      const BluetoothLowEnergyCharacteristicsFinder::SuccessCallback&
          success_callback,
      const BluetoothLowEnergyCharacteristicsFinder::ErrorCallback&
          error_callback);

  // namespace Connection:
  void SendMessageImpl(std::unique_ptr<WireMessage> message) override;

  // device::BluetoothAdapter::Observer:
  void DeviceChanged(device::BluetoothAdapter* adapter,
                     device::BluetoothDevice* device) override;
  void DeviceRemoved(device::BluetoothAdapter* adapter,
                     device::BluetoothDevice* device) override;
  void GattCharacteristicValueChanged(
      device::BluetoothAdapter* adapter,
      device::BluetoothRemoteGattCharacteristic* characteristic,
      const Packet& value) override;

 private:
  enum WriteRequestType {
    REGULAR,
    MESSAGE_COMPLETE,
    CONNECTION_REQUEST,
    CONNECTION_CLOSE
  };

  // Represents a request to write |value| to a some characteristic.
  // |is_last_write_for_wire_messsage| indicates whether this request
  // corresponds to the last write request for some wire message.
  struct WriteRequest {
    WriteRequest(const Packet& val,
                 WriteRequestType request_type,
                 std::shared_ptr<WireMessage> message);
    WriteRequest(const Packet& val, WriteRequestType request_type);
    WriteRequest(const WriteRequest& other);
    ~WriteRequest();

    Packet value;
    WriteRequestType request_type;
    std::shared_ptr<WireMessage> message;
    int number_of_failed_attempts;
  };

  void SetSubStatus(SubStatus status);

  // Creates the GATT connection with |remote_device|.
  void CreateGattConnection();

  // Called when a GATT connection is created.
  void OnGattConnectionCreated(
      std::unique_ptr<device::BluetoothGattConnection> gatt_connection);

  // Callback called when there is an error creating the GATT connection.
  void OnCreateGattConnectionError(
      device::BluetoothDevice::ConnectErrorCode error_code);

  // Callback called when |tx_characteristic_| and |rx_characteristic_| were
  // found.
  void OnCharacteristicsFound(const RemoteAttribute& service,
                              const RemoteAttribute& tx_characteristic,
                              const RemoteAttribute& rx_characteristic);

  // Callback called there was an error finding the characteristics.
  void OnCharacteristicsFinderError(const RemoteAttribute& tx_characteristic,
                                    const RemoteAttribute& rx_characteristic);

  // Starts a notify session for |rx_characteristic_| when ready
  // (SubStatus::CHARACTERISTICS_FOUND).
  void StartNotifySession();

  // Called when a notification session is successfully started for
  // |rx_characteristic_| characteristic.
  void OnNotifySessionStarted(
      std::unique_ptr<device::BluetoothGattNotifySession> notify_session);

  // Called when there is an error starting a notification session for
  // |rx_characteristic_| characteristic.
  void OnNotifySessionError(device::BluetoothGattService::GattErrorCode);

  // Stops |notify_session_|.
  void StopNotifySession();

  // Sends a connection request to server if ready
  // (SubStatus::NOTIFY_SESSION_READY).
  void SendConnectionRequest();

  // Completes and updates the status accordingly.
  void CompleteConnection();

  // This is the only entry point for WriteRequests, which are processed
  // accordingly the following flow:
  // 1) |request| is enqueued;
  // 2) |request| will be processed by ProcessNextWriteRequest() when there is
  // no pending write request;
  // 3) |request| will be dequeued when it's successfully processed
  // (OnRemoteCharacteristicWritten());
  // 4) |request| is not dequeued if it fails
  // (OnWriteRemoteCharacteristicError()), it remains on the queue and will be
  // retried. |request| will remain on the queue until it succeeds or it
  // triggers a Disconnect() call (after |max_number_of_tries_|).
  void WriteRemoteCharacteristic(const WriteRequest& request);

  // Processes the next request in |write_requests_queue_|.
  void ProcessNextWriteRequest();

  // Called when the
  // BluetoothRemoteGattCharacteristic::RemoteCharacteristicWrite() is
  // successfully complete.
  void OnRemoteCharacteristicWritten();

  // Called when there is an error writing to the remote characteristic
  // |tx_characteristic_|.
  void OnWriteRemoteCharacteristicError(
      device::BluetoothRemoteGattService::GattErrorCode error);

  void OnPacketReceiverError();

  // Prints the time elapsed since |Connect()| was called.
  void PrintTimeElapsed();

  // Returns the service corresponding to |remote_service_| in the current
  // device.
  device::BluetoothRemoteGattService* GetRemoteService();

  // Returns the characteristic corresponding to |identifier| in the current
  // service.
  device::BluetoothRemoteGattCharacteristic* GetGattCharacteristic(
      const std::string& identifier);

  // Get the reason that the other side of the connection decided to close the
  // connection.
  // Will crash if the receiver is not in CONNECTION_CLOSED state.
  std::string GetReasonForClose();

  // Returns the device corresponding to |device_address_|.
  device::BluetoothDevice* GetBluetoothDevice();

  // The device to which to connect.
  const std::string device_address_;

  // The Bluetooth adapter over which the Bluetooth connection will be made.
  scoped_refptr<device::BluetoothAdapter> adapter_;

  // Remote service the |gatt_connection_| was established with.
  RemoteAttribute remote_service_;

  // uWeave packet generator.
  std::unique_ptr<BluetoothLowEnergyWeavePacketGenerator> packet_generator_;

  // uWeave packet receiver.
  std::unique_ptr<BluetoothLowEnergyWeavePacketReceiver> packet_receiver_;

  // Characteristic used to send data to the remote device.
  RemoteAttribute tx_characteristic_;

  // Characteristic used to receive data from the remote device.
  RemoteAttribute rx_characteristic_;

  // Throttles repeated connection attempts to the same device. This is a
  // workaround for crbug.com/508919. Not owned, must outlive this instance.
  BluetoothThrottler* bluetooth_throttler_;

  scoped_refptr<base::TaskRunner> task_runner_;

  // The GATT connection with the remote device.
  std::unique_ptr<device::BluetoothGattConnection> gatt_connection_;

  // The characteristics finder for remote device.
  std::unique_ptr<BluetoothLowEnergyCharacteristicsFinder>
      characteristic_finder_;

  // The notify session for |rx_characteristic|.
  std::unique_ptr<device::BluetoothGattNotifySession> notify_session_;

  // Internal connection status
  SubStatus sub_status_;

  // Bytes already received for the current receive operation.
  std::string incoming_bytes_buffer_;

  // Indicates there is a
  // BluetoothRemoteGattCharacteristic::WriteRemoteCharacteristic
  // operation pending.
  bool write_remote_characteristic_pending_;

  std::queue<WriteRequest> write_requests_queue_;

  // Stores when the instace was created.
  base::TimeTicks start_time_;

  base::WeakPtrFactory<BluetoothLowEnergyWeaveClientConnection>
      weak_ptr_factory_;

  DISALLOW_COPY_AND_ASSIGN(BluetoothLowEnergyWeaveClientConnection);
};

}  // namespace weave

}  // namespace cryptauth

#endif  // COMPONENTS_CRYPTAUTH_BLE_BLUETOOTH_LOW_ENERGY_WEAVE_CLIENT_CONNECTION_H_