+++ /dev/null
-/******************************************************************************
- *
- * 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_core_counter"
-
-#include <assert.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <pthread.h>
-#include <stdarg.h>
-#include <stdatomic.h>
-#include <string.h>
-#include <sys/eventfd.h>
-
-#include "btcore/include/counter.h"
-#include "btcore/include/module.h"
-#include "osi/include/allocator.h"
-#include "osi/include/hash_functions.h"
-#include "osi/include/hash_map.h"
-#include "osi/include/list.h"
-#include "osi/include/log.h"
-#include "osi/include/osi.h"
-#include "osi/include/socket.h"
-#include "osi/include/thread.h"
-
-typedef int (*handler_t)(socket_t * socket);
-
-typedef struct counter_t {
- _Atomic(int64_t) val;
-} counter_t;
-
-typedef struct hash_element_t {
- const char *key;
- counter_t *val;
-} hash_element_t;
-
-typedef struct counter_data_cb_t {
- counter_iter_cb counter_iter_cb;
- void *user_context;
-} counter_data_cb_t;
-
-typedef struct {
- socket_t *socket;
- uint8_t buffer[256];
- size_t buffer_size;
-} client_t;
-
-typedef struct {
- const char *name;
- const char *help;
- handler_t handler;
-} command_t;
-
-// Counter core
-static hash_map_t *hash_map_counter_;
-static pthread_mutex_t hash_map_lock_;
-static int counter_cnt_;
-
-// Counter port access
-static socket_t *listen_socket_;
-static thread_t *thread_;
-static list_t *clients_;
-
-static void accept_ready(socket_t *socket, void *context);
-static void read_ready(socket_t *socket, void *context);
-static void client_free(void *ptr);
-static const command_t *find_command(const char *name);
-static void output(socket_t *socket, const char* format, ...);
-
-// Commands
-static int help(socket_t *socket);
-static int show(socket_t *socket);
-static int set(socket_t *socket);
-static int quit(socket_t *socket);
-
-static const command_t commands[] = {
- { "help", "<command> - show help text for <command>", help},
- { "quit", "<command> - Quit and exit", quit},
- { "set", "<counter> - Set something", set},
- { "show", "<counter> - Show counters", show},
-};
-
-static counter_t *counter_new_(counter_data_t initial_val);
-static void counter_free_(counter_t *counter);
-
-static hash_element_t *hash_element_new_(void);
-// NOTE: The parameter datatype is void in order to satisfy the hash
-// data free function signature
-static void hash_element_free_(void *data);
-
-static struct counter_t *name_to_counter_(const char *name);
-static bool counter_foreach_cb_(hash_map_entry_t *hash_map_entry, void *context);
-
-static bool counter_socket_open(void);
-static void counter_socket_close(void);
-
-static const int COUNTER_NUM_BUCKETS = 53;
-
-// TODO(cmanton) Friendly interface, but may remove for automation
-const char *WELCOME = "Welcome to counters\n";
-const char *PROMPT = "\n> ";
-const char *GOODBYE = "Quitting... Bye !!";
-
-// TODO(cmanton) Develop port strategy; or multiplex all bt across single port
-static const port_t LISTEN_PORT = 8879;
-
-static future_t *counter_init(void) {
- assert(hash_map_counter_ == NULL);
- pthread_mutex_init(&hash_map_lock_, NULL);
- hash_map_counter_ = hash_map_new(COUNTER_NUM_BUCKETS, hash_function_string,
- NULL, hash_element_free_, NULL);
- if (hash_map_counter_ == NULL) {
- LOG_ERROR(LOG_TAG, "%s unable to allocate resources", __func__);
- return future_new_immediate(FUTURE_FAIL);
- }
-
- if (!counter_socket_open()) {
- LOG_ERROR(LOG_TAG, "%s unable to open counter port", __func__);
- return future_new_immediate(FUTURE_FAIL);
- }
- return future_new_immediate(FUTURE_SUCCESS);
-}
-
-static future_t *counter_clean_up(void) {
- counter_socket_close();
- hash_map_free(hash_map_counter_);
- pthread_mutex_destroy(&hash_map_lock_);
- hash_map_counter_ = NULL;
- return future_new_immediate(FUTURE_SUCCESS);
-}
-
-EXPORT_SYMBOL module_t counter_module = {
- .name = COUNTER_MODULE,
- .init = counter_init,
- .start_up = NULL,
- .shut_down = NULL,
- .clean_up = counter_clean_up,
- .dependencies = {NULL},
-};
-
-void counter_set(const char *name, counter_data_t val) {
- assert(name != NULL);
- counter_t *counter = name_to_counter_(name);
- if (counter)
- atomic_store(&counter->val, val);
-}
-
-void counter_add(const char *name, counter_data_t val) {
- assert(name != NULL);
- counter_t *counter = name_to_counter_(name);
- if (counter) {
- atomic_fetch_add(&counter->val, val);
- }
-}
-
-bool counter_foreach(counter_iter_cb cb, void *context) {
- assert(cb != NULL);
- counter_data_cb_t counter_cb_data = {
- cb,
- context
- };
-
- hash_map_foreach(hash_map_counter_, counter_foreach_cb_, &counter_cb_data);
- return true;
-}
-
-static counter_t *counter_new_(counter_data_t initial_val) {
- counter_t *counter = (counter_t *)osi_calloc(sizeof(counter_t));
-
- atomic_store(&counter->val, initial_val);
- return counter;
-}
-
-static void counter_free_(counter_t *counter) {
- osi_free(counter);
-}
-
-static hash_element_t *hash_element_new_(void) {
- return (hash_element_t *)osi_calloc(sizeof(hash_element_t));
-}
-
-static void hash_element_free_(void *data) {
- hash_element_t *hash_element = (hash_element_t *)data;
- // We don't own the key
- counter_free_(hash_element->val);
- osi_free(hash_element);
-}
-
-// Returns a counter from the |hash_map_counter_|. Creates
-// a new one if not found and inserts into |hash_map_counter_|.
-// Returns NULL upon memory allocation failure.
-static counter_t *name_to_counter_(const char *name) {
- assert(hash_map_counter_ != NULL);
- if (hash_map_has_key(hash_map_counter_, name))
- return (counter_t *)hash_map_get(hash_map_counter_, name);
-
- pthread_mutex_lock(&hash_map_lock_);
- // On the uncommon path double check to make sure that another thread has
- // not already created this counter
- counter_t *counter = (counter_t *)hash_map_get(hash_map_counter_, name);
- if (counter)
- goto exit;
-
- counter = counter_new_(0);
- if (!counter) {
- LOG_ERROR(LOG_TAG, "%s unable to create new counter name:%s", __func__, name);
- goto exit;
- }
-
- hash_element_t *element = hash_element_new_();
- if (!element) {
- LOG_ERROR(LOG_TAG, "%s unable to create counter element name:%s", __func__, name);
- counter_free_(counter);
- counter = NULL;
- goto exit;
- }
-
- element->key = name;
- element->val = counter;
- if (!hash_map_set(hash_map_counter_, name, counter)) {
- LOG_ERROR(LOG_TAG, "%s unable to set new counter into hash map name:%s", __func__, name);
- hash_element_free_(element);
- counter_free_(counter);
- counter = NULL;
- }
-
- exit:;
- pthread_mutex_unlock(&hash_map_lock_);
- return counter;
-}
-
-static bool counter_foreach_cb_(hash_map_entry_t *hash_map_entry, void *context) {
- assert(hash_map_entry != NULL);
- const char *key = (const char *)hash_map_entry->key;
- counter_data_t data = *(counter_data_t *)hash_map_entry->data;
- counter_data_cb_t *counter_cb_data = (counter_data_cb_t *)context;
- counter_cb_data->counter_iter_cb(key, data, counter_cb_data->user_context);
- return true;
-}
-
-static bool counter_socket_open(void) {
-#if (!defined(BT_NET_DEBUG) || (BT_NET_DEBUG != TRUE))
- return true; // Disable using network sockets for security reasons
-#endif
-
- assert(listen_socket_ == NULL);
- assert(thread_ == NULL);
- assert(clients_ == NULL);
-
- clients_ = list_new(client_free);
- if (!clients_) {
- LOG_ERROR(LOG_TAG, "%s unable to create counter clients list", __func__);
- goto error;
- }
-
- thread_ = thread_new("counter_socket");
- if (!thread_) {
- LOG_ERROR(LOG_TAG, "%s unable to create counter thread", __func__);
- goto error;
- }
-
- listen_socket_ = socket_new();
- if (!listen_socket_) {
- LOG_ERROR(LOG_TAG, "%s unable to create listen socket", __func__);
- goto error;
- }
-
- if (!socket_listen(listen_socket_, LISTEN_PORT)) {
- LOG_ERROR(LOG_TAG, "%s unable to setup listen socket", __func__);
- goto error;
- }
-
- LOG_INFO(LOG_TAG, "%s opened counter server socket", __func__);
- socket_register(listen_socket_, thread_get_reactor(thread_), NULL, accept_ready, NULL);
- return true;
-
-error:;
- counter_socket_close();
- return false;
-}
-
-static void counter_socket_close(void) {
-#if (!defined(BT_NET_DEBUG) || (BT_NET_DEBUG != TRUE))
- return; // Disable using network sockets for security reasons
-#endif
-
- socket_free(listen_socket_);
- thread_free(thread_);
- list_free(clients_);
-
- listen_socket_ = NULL;
- thread_ = NULL;
- clients_ = NULL;
-
- LOG_INFO(LOG_TAG, "%s closed counter server socket", __func__);
-}
-
-static bool monitor_counter_iter_cb(const char *name, counter_data_t val, void *context) {
- socket_t *socket = (socket_t *)context;
- output(socket, "counter:%s val:%lld\n", name, val);
- return true;
-}
-
-static void client_free(void *ptr) {
- if (!ptr)
- return;
-
- client_t *client = (client_t *)ptr;
- socket_free(client->socket);
- osi_free(client);
-}
-
-static void accept_ready(socket_t *socket, UNUSED_ATTR void *context) {
- assert(socket != NULL);
- assert(socket == listen_socket_);
-
- LOG_INFO(LOG_TAG, "%s accepted OSI monitor socket", __func__);
- socket = socket_accept(socket);
- if (!socket)
- return;
-
- client_t *client = (client_t *)osi_calloc(sizeof(client_t));
- client->socket = socket;
-
- if (!list_append(clients_, client)) {
- LOG_ERROR(LOG_TAG, "%s unable to add client to list", __func__);
- client_free(client);
- return;
- }
-
- socket_register(socket, thread_get_reactor(thread_), client, read_ready, NULL);
-
- output(socket, WELCOME);
- output(socket, PROMPT);
-}
-
-static void read_ready(socket_t *socket, void *context) {
- assert(socket != NULL);
-
- client_t *client = (client_t *)context;
-
- ssize_t ret = socket_read(socket, client->buffer + client->buffer_size, sizeof(client->buffer) - client->buffer_size);
- if (ret == 0 || (ret == -1 && ret != EWOULDBLOCK && ret != EAGAIN)) {
- list_remove(clients_, client);
- return;
- }
-
- // Replace newline with end of string termination
- // TODO(cmanton) Need proper semantics
- for (size_t i = ret - 1; i > 0; --i) {
- if (client->buffer[i] < 16)
- *(client->buffer + i) = 0;
- else
- break;
- }
-
- const command_t *command = find_command((const char *)client->buffer);
- if (!command) {
- output(socket, "unable to find command %s\n", client->buffer);
- } else {
- int rc = command->handler(socket);
- if (rc == 1) {
- output(socket, GOODBYE);
- socket_free(socket);
- return;
- }
- }
- output(socket, PROMPT);
-}
-
-static void output(socket_t *socket, const char* format, ...) {
- char dest[4096];
- va_list argptr;
- va_start(argptr, format);
- vsprintf(dest, format, argptr);
- va_end(argptr);
- socket_write(socket, dest, strlen(dest));
-}
-
-static int help(UNUSED_ATTR socket_t *socket) {
- output(socket, "help command unimplemented\n");
- return 0;
-}
-
-static int quit(UNUSED_ATTR socket_t *socket) {
- return 1;
-}
-
-static int set(UNUSED_ATTR socket_t *socket) {
- output(socket, "set command unimplemented\n");
- return 0;
-}
-
-static int show(socket_t *socket) {
- output(socket, "counter count registered:%d\n", counter_cnt_);
- counter_foreach(monitor_counter_iter_cb, (void *)socket);
- return 0;
-}
-
-static const command_t *find_command(const char *name) {
- for (size_t i = 0; i < ARRAY_SIZE(commands); ++i)
- if (!strcmp(commands[i].name, name))
- return &commands[i];
- return NULL;
-}
+++ /dev/null
-/******************************************************************************
- *
- * 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.
- *
- ******************************************************************************/
-
-#include <gtest/gtest.h>
-#include "osi/test/AllocationTestHarness.h"
-
-extern "C" {
-#include "btcore/include/counter.h"
-#include "btcore/include/module.h"
-
-extern module_t counter_module;
-} // "C"
-
-static const uint64_t COUNTER_TEST_TEN = 10;
-
-typedef struct mycounter_t {
- const char *name;
- uint64_t val;
- bool found;
-} mycounter_t;
-
-static bool counter_iter(const char *name, counter_data_t val, void *context) {
- mycounter_t *mycounter = (mycounter_t *)context;
- if (!strcmp(name, mycounter->name)) {
- mycounter->val = val;
- mycounter->found = true;
- return false;
- }
- return true;
-}
-
-static bool find_val(const char *name, uint64_t *val) {
- mycounter_t mycounter;
-
- mycounter.val = 0;
- mycounter.name = name;
- mycounter.found = false;
- counter_foreach(counter_iter, &mycounter);
- *val = mycounter.val;
- if (mycounter.found)
- return true;
- return false;
-}
-
-class CounterTest : public AllocationTestHarness {
- protected:
- virtual void SetUp() {
- counter_module.init();
- }
-
- virtual void TearDown() {
- counter_module.clean_up();
- }
-};
-
-TEST_F(CounterTest, counter_no_exist) {
- uint64_t val;
-
- EXPECT_FALSE(find_val("one.two.three", &val));
-}
-
-TEST_F(CounterTest, counter_inc_dec) {
- uint64_t val;
-
- counter_add("one.two.three", 1);
-
- EXPECT_TRUE(find_val("one.two.three", &val));
- EXPECT_EQ((uint64_t)1, val);
-
- counter_add("one.two.three", 1);
- EXPECT_TRUE(find_val("one.two.three", &val));
- EXPECT_EQ((uint64_t)2, val);
-
- counter_add("one.two.three", -1);
- EXPECT_TRUE(find_val("one.two.three", &val));
- EXPECT_EQ((uint64_t)1, val);
-}
-
-TEST_F(CounterTest, counter_get_set) {
- uint64_t val;
-
- counter_set("one.two.three", COUNTER_TEST_TEN);
- EXPECT_TRUE(find_val("one.two.three", &val));
- EXPECT_EQ(COUNTER_TEST_TEN, val);
-
- EXPECT_FALSE(find_val("foo.bar", &val));
-}