/******************************************************************************
*
* Copyright (C) 2014 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
#define LOG_TAG "bt_classic_peer"
#include "device/include/classic/peer.h"
#include <assert.h>
#include <cutils/log.h>
#include <pthread.h>
#include <stdbool.h>
#include "btcore/include/module.h"
#include "osi/include/allocator.h"
#include "osi/include/future.h"
#include "osi/include/hash_map.h"
#include "osi/include/osi.h"
struct classic_peer_t {
bt_bdaddr_t address;
};
static const size_t number_of_address_buckets = 42;
static bool initialized;
static pthread_mutex_t bag_of_peers_lock;
static hash_map_t *peers_by_address;
static bool bdaddr_equality_fn(const void *x, const void *y);
// Module lifecycle functions
static future_t *init(void) {
peers_by_address = hash_map_new(
number_of_address_buckets,
hash_function_bdaddr,
NULL,
osi_free,
bdaddr_equality_fn);
pthread_mutex_init(&bag_of_peers_lock, NULL);
initialized = true;
return NULL;
}
static future_t *clean_up(void) {
initialized = false;
hash_map_free(peers_by_address);
peers_by_address = NULL;
pthread_mutex_destroy(&bag_of_peers_lock);
return NULL;
}
EXPORT_SYMBOL const module_t classic_peer_module = {
.name = CLASSIC_PEER_MODULE,
.init = init,
.start_up = NULL,
.shut_down = NULL,
.clean_up = clean_up,
.dependencies = {
NULL
}
};
// Interface functions
classic_peer_t *classic_peer_by_address(bt_bdaddr_t *address) {
assert(initialized);
assert(address != NULL);
classic_peer_t *peer = hash_map_get(peers_by_address, address);
if (!peer) {
pthread_mutex_lock(&bag_of_peers_lock);
// Make sure it didn't get added in the meantime
peer = hash_map_get(peers_by_address, address);
if (peer)
goto done;
// Splice in a new peer struct on behalf of the caller.
peer = osi_calloc(sizeof(classic_peer_t));
peer->address = *address;
hash_map_set(peers_by_address, &peer->address, peer);
pthread_mutex_unlock(&bag_of_peers_lock);
}
done:
return peer;
}
const bt_bdaddr_t *classic_peer_get_address(classic_peer_t *peer) {
assert(peer != NULL);
return &peer->address;
}
// Internal functions
// Wrapper for bdaddr_equals used in the hash map of peers by address
static bool bdaddr_equality_fn(const void *x, const void *y) {
return bdaddr_equals((bt_bdaddr_t *)x, (bt_bdaddr_t *)y);
}