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
33 struct classic_peer_t {
34 bt_bdaddr_t address;
35 };
36
37 static const size_t number_of_address_buckets = 42;
38
39 static bool initialized;
40 static pthread_mutex_t bag_of_peers_lock;
41 static hash_map_t *peers_by_address;
42
43 static bool bdaddr_equality_fn(const void *x, const void *y);
44
45 // Module lifecycle functions
46
init(void)47 static 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
clean_up(void)61 static 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
71 const 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
classic_peer_by_address(bt_bdaddr_t * address)84 classic_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
106 done:
107 return peer;
108 }
109
classic_peer_get_address(classic_peer_t * peer)110 const 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
bdaddr_equality_fn(const void * x,const void * y)118 static bool bdaddr_equality_fn(const void *x, const void *y) {
119 return bdaddr_equals((bt_bdaddr_t *)x, (bt_bdaddr_t *)y);
120 }
121