1/******************************************************************************
2 *
3 *  Copyright (C) 2014 Google, Inc.
4 *
5 *  Licensed under the Apache License, Version 2.0 (the "License");
6 *  you may not use this file except in compliance with the License.
7 *  You may obtain a copy of the License at:
8 *
9 *  http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 *
17 ******************************************************************************/
18
19#define LOG_TAG "bt_classic_peer"
20
21#include <assert.h>
22#include <cutils/log.h>
23#include <pthread.h>
24#include <stdbool.h>
25
26#include "btcore/include/module.h"
27#include "device/include/classic/peer.h"
28#include "osi/include/allocator.h"
29#include "osi/include/future.h"
30#include "osi/include/hash_map.h"
31#include "osi/include/osi.h"
32
33struct classic_peer_t {
34  bt_bdaddr_t address;
35};
36
37static const size_t number_of_address_buckets = 42;
38
39static bool initialized;
40static pthread_mutex_t bag_of_peers_lock;
41static hash_map_t *peers_by_address;
42
43static bool bdaddr_equality_fn(const void *x, const void *y);
44
45// Module lifecycle functions
46
47static future_t *init(void) {
48  peers_by_address = hash_map_new(
49    number_of_address_buckets,
50    hash_function_bdaddr,
51    NULL,
52    osi_free,
53    bdaddr_equality_fn);
54
55  pthread_mutex_init(&bag_of_peers_lock, NULL);
56
57  initialized = true;
58  return NULL;
59}
60
61static future_t *clean_up(void) {
62  initialized = false;
63
64  hash_map_free(peers_by_address);
65  peers_by_address = NULL;
66
67  pthread_mutex_destroy(&bag_of_peers_lock);
68  return NULL;
69}
70
71const module_t classic_peer_module = {
72  .name = CLASSIC_PEER_MODULE,
73  .init = init,
74  .start_up = NULL,
75  .shut_down = NULL,
76  .clean_up = clean_up,
77  .dependencies = {
78    NULL
79  }
80};
81
82// Interface functions
83
84classic_peer_t *classic_peer_by_address(bt_bdaddr_t *address) {
85  assert(initialized);
86  assert(address != NULL);
87
88  classic_peer_t *peer = hash_map_get(peers_by_address, address);
89
90  if (!peer) {
91    pthread_mutex_lock(&bag_of_peers_lock);
92
93    // Make sure it didn't get added in the meantime
94    peer = hash_map_get(peers_by_address, address);
95    if (peer)
96      goto done;
97
98    // Splice in a new peer struct on behalf of the caller.
99    peer = osi_calloc(sizeof(classic_peer_t));
100    peer->address = *address;
101    hash_map_set(peers_by_address, &peer->address, peer);
102
103    pthread_mutex_unlock(&bag_of_peers_lock);
104  }
105
106done:
107  return peer;
108}
109
110const bt_bdaddr_t *classic_peer_get_address(classic_peer_t *peer) {
111  assert(peer != NULL);
112  return &peer->address;
113}
114
115// Internal functions
116
117// Wrapper for bdaddr_equals used in the hash map of peers by address
118static bool bdaddr_equality_fn(const void *x, const void *y) {
119  return bdaddr_equals((bt_bdaddr_t *)x, (bt_bdaddr_t *)y);
120}
121