summaryrefslogtreecommitdiff
path: root/src/components/transport_manager/include/transport_manager/transport_manager_impl.h
blob: 5e97a5567e7209687def0b2dec65f234df48c1c8 (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
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
/*
 * Copyright (c) 2016, Ford Motor Company
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following
 * disclaimer in the documentation and/or other materials provided with the
 * distribution.
 *
 * Neither the name of the Ford Motor Company nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef SRC_COMPONENTS_TRANSPORT_MANAGER_INCLUDE_TRANSPORT_MANAGER_TRANSPORT_MANAGER_IMPL_H_
#define SRC_COMPONENTS_TRANSPORT_MANAGER_INCLUDE_TRANSPORT_MANAGER_TRANSPORT_MANAGER_IMPL_H_

#include <algorithm>
#include <functional>
#include <list>
#include <map>
#include <queue>
#include <tuple>
#include <utility>
#include <vector>

#include "utils/rwlock.h"
#include "utils/timer.h"

#include "protocol/common.h"
#include "transport_manager/transport_adapter/transport_adapter_listener_impl.h"
#include "transport_manager/transport_manager.h"
#include "transport_manager/transport_manager_listener.h"
#ifdef TELEMETRY_MONITOR
#include "telemetry_monitor/telemetry_observable.h"
#include "transport_manager/telemetry_observer.h"
#endif  // TELEMETRY_MONITOR
#include "transport_manager/transport_adapter/transport_adapter_event.h"
#include "transport_manager/transport_manager_settings.h"
#include "utils/threads/message_loop_thread.h"

namespace transport_manager {

typedef threads::MessageLoopThread<std::queue<protocol_handler::RawMessagePtr> >
    RawMessageLoopThread;
typedef threads::MessageLoopThread<std::queue<TransportAdapterEvent> >
    TransportAdapterEventLoopThread;
typedef std::shared_ptr<timer::Timer> TimerSPtr;
typedef std::map<DeviceUID, TransportAdapter*> DeviceToAdapterMap;

/**
 * @brief Implementation of transport manager.s
 */
class TransportManagerImpl
    : public TransportManager,
      public RawMessageLoopThread::Handler,
      public TransportAdapterEventLoopThread::Handler
#ifdef TELEMETRY_MONITOR
    ,
      public telemetry_monitor::TelemetryObservable<TMTelemetryObserver>
#endif  // TELEMETRY_MONITOR
{
 public:
  struct Connection {
    ConnectionUID id;
    DeviceUID device;
    ApplicationHandle application;
  };

 private:
  /**
   * @brief Structure that contains internal connection parameters
   */
  struct ConnectionInternal : public Connection {
    TransportManagerImpl* transport_manager;
    TransportAdapter* transport_adapter;
    TimerSPtr timer;
    bool shutdown_;
    DeviceHandle device_handle_;
    int messages_count;
    bool active_;

    ConnectionInternal(TransportManagerImpl* transport_manager,
                       TransportAdapter* transport_adapter,
                       const ConnectionUID id,
                       const DeviceUID& dev_id,
                       const ApplicationHandle& app_id,
                       const DeviceHandle device_handle);

    void DisconnectFailedRoutine();
  };

 public:
  /**
   * @brief Constructor.
   **/
  explicit TransportManagerImpl(const TransportManagerSettings& settings);

  /**
   * @brief Destructor.
   **/
  virtual ~TransportManagerImpl();

  /**
   * @brief Initialize transport manager.
   *
   * @return Code error.
   */
  int Init(resumption::LastState& last_state) OVERRIDE;

  /**
   * Reinitializes transport manager
   * @return Error code
   */
  virtual int Reinit() OVERRIDE;

  virtual void Deinit() OVERRIDE;

  void StopEventsProcessing() OVERRIDE;

  void StartEventsProcessing() OVERRIDE;

  /**
   * @brief Start scanning for new devices.
   *
   * @return Code error.
   **/
  int SearchDevices() OVERRIDE;

  void AddCloudDevice(
      const transport_manager::transport_adapter::CloudAppProperties&
          cloud_properties) OVERRIDE;

  void RemoveCloudDevice(const DeviceHandle device_id) OVERRIDE;

  /**
   * @brief Connect to all applications discovered on device.
   *
   * @param device_id Handle of device to connect to.
   *
   * @return Code error.
   **/
  int ConnectDevice(const DeviceHandle device_id) OVERRIDE;

  /**
   * @brief Retrieves the connection status of a given device
   *
   * @param device_handle Handle of device to query
   *
   * @return The connection status of the given device
   */
  ConnectionStatus GetConnectionStatus(
      const DeviceHandle& device_handle) const OVERRIDE;

  /**
   * @brief Disconnect from all applications connected on device.
   *
   * @param device_id Handle of device to Disconnect from.
   *
   * @return Code error.
   **/
  int DisconnectDevice(const DeviceHandle device_id) OVERRIDE;

  /**
   * @brief Disconnect from applications connected on device by connection
   *unique identifier.
   *
   * @param connection Connection unique identifier.
   *
   * @return Code error.
   **/
  int Disconnect(const ConnectionUID connection_id) OVERRIDE;

  /**
   * @brief Disconnect and clear all unreceived data.
   *
   * @param connection Connection unique identifier.
   */
  int DisconnectForce(const ConnectionUID connection_id) OVERRIDE;
  /**
   * @brief Post new message in queue for massages destined to device.
   *
   * @param message Smart pointer to the raw massage.
   *
   * @return Code error.
   **/
  int SendMessageToDevice(
      const protocol_handler::RawMessagePtr message) OVERRIDE;

  /**
   * @brief RunAppOnDevice allows to run specific application on the certain
   *device.
   *
   * @param device_handle device identifier to run application on.
   *
   * @param bundle_id application id also known as bundle id on some devices to
   *run.
   */
  void RunAppOnDevice(const DeviceHandle device_handle,
                      const std::string& bundle_id) OVERRIDE;

  /**
   * @brief Post event in the event queue.
   *
   * @param event Current event information.
   *
   * @return Code error.
   **/
  int ReceiveEventFromDevice(const TransportAdapterEvent& event) OVERRIDE;

  /**
   * @brief Post listener to the container of transport manager listeners.
   *
   * @param listener Pointer to the transport manager listener.
   *
   * @return Code error.
   **/
  int AddEventListener(TransportManagerListener* listener) OVERRIDE;

  int Stop() OVERRIDE;

  /**
   * @brief Add device adapter to the container of device adapters.
   *
   * @param transport_adapter Smart pointer to the device adapter.
   *
   * @return Code error.
   **/
  int AddTransportAdapter(
      transport_adapter::TransportAdapter* transport_adapter) OVERRIDE;

  /**
   * @brief Remove device from the container that hold devices.
   *
   * @param device Handle of device.
   *
   * @return Code error.
   **/
  int RemoveDevice(const DeviceHandle device) OVERRIDE;

  int PerformActionOnClients(
      const TransportAction required_action) const OVERRIDE;

  /**
   * @brief OnDeviceListUpdated updates device list and sends appropriate
   * notifications to listeners in case of something is changed
   * @param ta Transport adapter to check for updated devices state
   */
  void OnDeviceListUpdated(TransportAdapter* ta);

#ifdef TELEMETRY_MONITOR
  /**
   * @brief Setup observer for time metric.
   *
   * @param observer - pointer to observer
   */
  void SetTelemetryObserver(TMTelemetryObserver* observer);
#endif  // TELEMETRY_MONITOR

  /**
   * @brief Constructor.
   **/
  TransportManagerImpl();

  const TransportManagerSettings& get_settings() const;

 protected:
  template <class Proc, class... Args>
  void RaiseEvent(Proc proc, Args... args) {
    for (TransportManagerListenerList::iterator it =
             transport_manager_listener_.begin();
         it != transport_manager_listener_.end();
         ++it) {
      ((*it)->*proc)(args...);
    }
  }

  /**
   * @brief Put massage in the container of massages.
   *
   * @param message Smart pointer to the raw massage.
   **/
  void PostMessage(const ::protocol_handler::RawMessagePtr message);

  void Handle(::protocol_handler::RawMessagePtr msg);
  void Handle(TransportAdapterEvent msg);

  /**
   * @brief Post event to the container of events.
   *
   * @param event Event of device adapter.
   **/
  void PostEvent(const TransportAdapterEvent& event);

  typedef std::list<TransportManagerListener*> TransportManagerListenerList;
  /**
   * @brief listener that would be called when TM's event happened.
   **/
  TransportManagerListenerList transport_manager_listener_;

  /**
   * @brief Flag that TM is initialized
   */
  bool is_initialized_;

#ifdef TELEMETRY_MONITOR
  TMTelemetryObserver* metric_observer_;
#endif  // TELEMETRY_MONITOR

 private:
  /**
   * @brief Structure that contains conversion functions (Device ID -> Device
   * Handle; Device Handle -> Device ID)
   */
  struct Handle2GUIDConverter {
    /**
     * @brief ConversionTable Records uid/connection type/handle
     */
    typedef std::vector<std::tuple<DeviceUID, std::string, DeviceHandle> >
        ConversionTable;

    /**
     * @brief The HandleFinder struct helper to search for hanlde in coversion
     * table
     */
    struct HandleFinder {
      explicit HandleFinder(const DeviceHandle& look_for)
          : look_for_(look_for) {}

      bool operator()(const ConversionTable::value_type value) const {
        return look_for_ == std::get<2>(value);
      }

      const DeviceHandle look_for_;
    };

    /**
     * @brief UidToHandle Converts UID to handle considering connection type as
     * UID may be the same in case device is connected over Bluetooth/USB (e.g.
     * for IAP2)
     * @param dev_uid Device UID
     * @param connection_type Connection type
     * @return Device handle
     */
    DeviceHandle UidToHandle(const DeviceUID& dev_uid,
                             const std::string& connection_type);

    /**
     * @brief HandleToUid Converts handle to device UID
     * @param handle Device handle
     * @return Device UID
     */
    DeviceUID HandleToUid(const DeviceHandle handle);

   private:
    ConversionTable conversion_table_;
    std::hash<std::string> hash_function_;
    sync_primitives::RWLock conversion_table_lock_;
  };

  /**
   * @brief Converter variable (Device ID -> Device Handle; Device Handle ->
   * Device ID)
   */
  mutable Handle2GUIDConverter converter_;

#ifdef BUILD_TESTS
 public:
  Handle2GUIDConverter& get_converter() {
    return converter_;
  }

 private:
#endif  // BUILD_TESTS

  explicit TransportManagerImpl(const TransportManagerImpl&);
  int connection_id_counter_;
  sync_primitives::RWLock connections_lock_;
  std::vector<ConnectionInternal> connections_;
  mutable sync_primitives::RWLock device_to_adapter_map_lock_;
  typedef std::map<DeviceUID, TransportAdapter*> DeviceToAdapterMap;
  DeviceToAdapterMap device_to_adapter_map_;
  std::vector<TransportAdapter*> transport_adapters_;
  /** For keep listeners which were add TMImpl */
  std::map<TransportAdapter*, TransportAdapterListenerImpl*>
      transport_adapter_listeners_;
  RawMessageLoopThread message_queue_;
  TransportAdapterEventLoopThread event_queue_;
  const TransportManagerSettings& settings_;
  typedef std::vector<std::pair<const TransportAdapter*, DeviceInfo> >
      DeviceInfoList;
  sync_primitives::RWLock device_list_lock_;
  DeviceInfoList device_list_;

  timer::Timer device_switch_timer_;
  sync_primitives::Lock device_lock_;
  DeviceUID device_to_reconnect_;

  std::atomic_bool events_processing_is_active_;
  sync_primitives::Lock events_processing_lock_;
  sync_primitives::ConditionalVariable events_processing_cond_var_;

  /**
   * @brief Adds new incoming connection to connections list
   * @param c New connection
   */
  void AddConnection(const ConnectionInternal& c);

  /**
   * @brief Removes connection from connections list
   * @param id Identifier of connection to be removed
   * @param transport_adapter Pointer to transport adapter
   * that holds connection
   */
  void RemoveConnection(const uint32_t id,
                        transport_adapter::TransportAdapter* transport_adapter);

  /**
   * @brief Deactivates all connections related to certain device
   * @param device_uid Device unique identifier
   */
  void DeactivateDeviceConnections(const DeviceUID& device_uid);
  /**
   * @brief Returns connection from connections list by connection identifier
   * @param id Connection identifier
   * @return Pointer to connection or NULL if connection could not be found
   */
  ConnectionInternal* GetConnection(const ConnectionUID id);

  /**
   * @brief Returns connection from connections list by device unique id
   * and application handle
   * @param device Device unique identifier
   * @param application Application handle
   * @return Pointer to connection or NULL if connection could not be found
   */
  ConnectionInternal* GetConnection(const DeviceUID& device,
                                    const ApplicationHandle& application);

  /**
   * @brief Returns active connection from connections list by device unique
   * id
   * and application handle
   * (this method returns only active connections as opposed to previous one)
   * @param device Device unique identifier
   * @param application Application handle
   * @return Pointer to connection or NULL if connection could not be found
   */
  ConnectionInternal* GetActiveConnection(const DeviceUID& device,
                                          const ApplicationHandle& application);

  /**
   * @brief TryDeviceSwitch in case USB device is connected and there is
   * appropriate Bluetooth device with same UUID stops Bluetooth device and
   * initiates switching sequence for upper layers. Also starts timer to wait
   * for sequence to complete.
   * @param ta Transport adapter having device to try switching sequence
   * At the moment implementation implies only IAP2-Bluetooth to IAP2-USB
   * switching
   */
  void TryDeviceSwitch(TransportAdapter* ta);

  void AddDataToContainer(
      ConnectionUID id,
      std::map<ConnectionUID, std::pair<unsigned int, unsigned char*> >&
          container,
      unsigned char* data,
      unsigned int data_size);
  bool GetFrameSize(unsigned char* data,
                    unsigned int data_size,
                    unsigned int& frame_size);
  bool GetFrame(std::map<ConnectionUID,
                         std::pair<unsigned int, unsigned char*> >& container,
                ConnectionUID id,
                unsigned int frame_size,
                unsigned char** frame);

  void DisconnectAllDevices();
  void TerminateAllAdapters();
  int InitAllAdapters();
  static Connection convert(const ConnectionInternal& p);

  /**
   * @brief ReconnectionTimeout notifies upper layers on switching sequence
   * timeout expiration
   */
  void ReconnectionTimeout();

  /**
   * @brief UpdateDeviceMapping handles internal device-to-adapter mapping,
   * performs its update on adding/removal of devices. Also used by IAP2
   * switching flow to substitute BT with USB transport
   * @param ta Pointer to transport adapter
   * @return True if mapping has been updated, otherwise - false
   */
  bool UpdateDeviceMapping(TransportAdapter* ta);

  /**
   * @brief Updates total device list with info from specific transport adapter.
   * @param ta Transport adapter
   */
  void UpdateDeviceList(TransportAdapter* ta);
};  // class TransportManagerImpl
}  // namespace transport_manager
#endif  // SRC_COMPONENTS_TRANSPORT_MANAGER_INCLUDE_TRANSPORT_MANAGER_TRANSPORT_MANAGER_IMPL_H_