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_core_counter"
20
21 #include <assert.h>
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <string.h>
25 #include <sys/eventfd.h>
26
27 #include "osi/include/allocator.h"
28 #include "osi/include/atomic.h"
29 #include "btcore/include/counter.h"
30 #include "osi/include/hash_map.h"
31 #include "osi/include/list.h"
32 #include "btcore/include/module.h"
33 #include "osi/include/osi.h"
34 #include "osi/include/hash_functions.h"
35 #include "osi/include/log.h"
36 #include "osi/include/socket.h"
37 #include "osi/include/thread.h"
38
39 typedef int (*handler_t)(socket_t * socket);
40
41 typedef struct counter_t {
42 atomic_s64_t val;
43 } counter_t;
44
45 typedef struct hash_element_t {
46 const char *key;
47 counter_t *val;
48 } hash_element_t;
49
50 typedef struct counter_data_cb_t {
51 counter_iter_cb counter_iter_cb;
52 void *user_context;
53 } counter_data_cb_t;
54
55 typedef struct {
56 socket_t *socket;
57 uint8_t buffer[256];
58 size_t buffer_size;
59 } client_t;
60
61 typedef struct {
62 const char *name;
63 const char *help;
64 handler_t handler;
65 } command_t;
66
67 // Counter core
68 static hash_map_t *hash_map_counter_;
69 static pthread_mutex_t hash_map_lock_;
70 static int counter_cnt_;
71
72 // Counter port access
73 static socket_t *listen_socket_;
74 static thread_t *thread_;
75 static list_t *clients_;
76
77 static void accept_ready(socket_t *socket, void *context);
78 static void read_ready(socket_t *socket, void *context);
79 static void client_free(void *ptr);
80 static const command_t *find_command(const char *name);
81 static void output(socket_t *socket, const char* format, ...);
82
83 // Commands
84 static int help(socket_t *socket);
85 static int show(socket_t *socket);
86 static int set(socket_t *socket);
87 static int quit(socket_t *socket);
88
89 static const command_t commands[] = {
90 { "help", "<command> - show help text for <command>", help},
91 { "quit", "<command> - Quit and exit", quit},
92 { "set", "<counter> - Set something", set},
93 { "show", "<counter> - Show counters", show},
94 };
95
96 static counter_t *counter_new_(counter_data_t initial_val);
97 static void counter_free_(counter_t *counter);
98
99 static hash_element_t *hash_element_new_(void);
100 // NOTE: The parameter datatype is void in order to satisfy the hash
101 // data free function signature
102 static void hash_element_free_(void *data);
103
104 static struct counter_t *name_to_counter_(const char *name);
105 static bool counter_foreach_cb_(hash_map_entry_t *hash_map_entry, void *context);
106
107 static bool counter_socket_open(void);
108 static void counter_socket_close(void);
109
110 static const int COUNTER_NUM_BUCKETS = 53;
111
112 // TODO(cmanton) Friendly interface, but may remove for automation
113 const char *WELCOME = "Welcome to counters\n";
114 const char *PROMPT = "\n> ";
115 const char *GOODBYE = "Quitting... Bye !!";
116
117 // TODO(cmanton) Develop port strategy; or multiplex all bt across single port
118 static const port_t LISTEN_PORT = 8879;
119
counter_init(void)120 static future_t *counter_init(void) {
121 assert(hash_map_counter_ == NULL);
122 pthread_mutex_init(&hash_map_lock_, NULL);
123 hash_map_counter_ = hash_map_new(COUNTER_NUM_BUCKETS, hash_function_string,
124 NULL, hash_element_free_, NULL);
125 if (hash_map_counter_ == NULL) {
126 LOG_ERROR("%s unable to allocate resources", __func__);
127 return future_new_immediate(FUTURE_FAIL);
128 }
129
130 if (!counter_socket_open()) {
131 LOG_ERROR("%s unable to open counter port", __func__);
132 return future_new_immediate(FUTURE_FAIL);
133 }
134 return future_new_immediate(FUTURE_SUCCESS);
135 }
136
counter_clean_up(void)137 static future_t *counter_clean_up(void) {
138 counter_socket_close();
139 hash_map_free(hash_map_counter_);
140 pthread_mutex_destroy(&hash_map_lock_);
141 hash_map_counter_ = NULL;
142 return future_new_immediate(FUTURE_SUCCESS);
143 }
144
145 module_t counter_module = {
146 .name = COUNTER_MODULE,
147 .init = counter_init,
148 .start_up = NULL,
149 .shut_down = NULL,
150 .clean_up = counter_clean_up,
151 .dependencies = {NULL},
152 };
153
counter_set(const char * name,counter_data_t val)154 void counter_set(const char *name, counter_data_t val) {
155 assert(name != NULL);
156 counter_t *counter = name_to_counter_(name);
157 if (counter)
158 atomic_store_s64(&counter->val, val);
159 }
160
counter_add(const char * name,counter_data_t val)161 void counter_add(const char *name, counter_data_t val) {
162 assert(name != NULL);
163 counter_t *counter = name_to_counter_(name);
164 if (counter) {
165 if (val == 1)
166 atomic_inc_prefix_s64(&counter->val);
167 else
168 atomic_add_s64(&counter->val, val);
169 }
170 }
171
counter_foreach(counter_iter_cb cb,void * context)172 bool counter_foreach(counter_iter_cb cb, void *context) {
173 assert(cb != NULL);
174 counter_data_cb_t counter_cb_data = {
175 cb,
176 context
177 };
178
179 hash_map_foreach(hash_map_counter_, counter_foreach_cb_, &counter_cb_data);
180 return true;
181 }
182
counter_new_(counter_data_t initial_val)183 static counter_t *counter_new_(counter_data_t initial_val) {
184 counter_t *counter = (counter_t *)osi_calloc(sizeof(counter_t));
185 if (!counter) {
186 return NULL;
187 }
188 atomic_store_s64(&counter->val, initial_val);
189 return counter;
190 }
191
counter_free_(counter_t * counter)192 static void counter_free_(counter_t *counter) {
193 osi_free(counter);
194 }
195
hash_element_new_(void)196 static hash_element_t *hash_element_new_(void) {
197 return (hash_element_t *)osi_calloc(sizeof(hash_element_t));
198 }
199
hash_element_free_(void * data)200 static void hash_element_free_(void *data) {
201 hash_element_t *hash_element = (hash_element_t *)data;
202 // We don't own the key
203 counter_free_(hash_element->val);
204 osi_free(hash_element);
205 }
206
207 // Returns a counter from the |hash_map_counter_|. Creates
208 // a new one if not found and inserts into |hash_map_counter_|.
209 // Returns NULL upon memory allocation failure.
name_to_counter_(const char * name)210 static counter_t *name_to_counter_(const char *name) {
211 assert(hash_map_counter_ != NULL);
212 if (hash_map_has_key(hash_map_counter_, name))
213 return (counter_t *)hash_map_get(hash_map_counter_, name);
214
215 pthread_mutex_lock(&hash_map_lock_);
216 // On the uncommon path double check to make sure that another thread has
217 // not already created this counter
218 counter_t *counter = (counter_t *)hash_map_get(hash_map_counter_, name);
219 if (counter)
220 goto exit;
221
222 counter = counter_new_(0);
223 if (!counter) {
224 LOG_ERROR("%s unable to create new counter name:%s", __func__, name);
225 goto exit;
226 }
227
228 hash_element_t *element = hash_element_new_();
229 if (!element) {
230 LOG_ERROR("%s unable to create counter element name:%s", __func__, name);
231 counter_free_(counter);
232 counter = NULL;
233 goto exit;
234 }
235
236 element->key = name;
237 element->val = counter;
238 if (!hash_map_set(hash_map_counter_, name, counter)) {
239 LOG_ERROR("%s unable to set new counter into hash map name:%s", __func__, name);
240 hash_element_free_(element);
241 counter_free_(counter);
242 counter = NULL;
243 }
244
245 exit:;
246 pthread_mutex_unlock(&hash_map_lock_);
247 return counter;
248 }
249
counter_foreach_cb_(hash_map_entry_t * hash_map_entry,void * context)250 static bool counter_foreach_cb_(hash_map_entry_t *hash_map_entry, void *context) {
251 assert(hash_map_entry != NULL);
252 const char *key = (const char *)hash_map_entry->key;
253 counter_data_t data = *(counter_data_t *)hash_map_entry->data;
254 counter_data_cb_t *counter_cb_data = (counter_data_cb_t *)context;
255 counter_cb_data->counter_iter_cb(key, data, counter_cb_data->user_context);
256 return true;
257 }
258
counter_socket_open(void)259 static bool counter_socket_open(void) {
260 #if (!defined(BT_NET_DEBUG) || (BT_NET_DEBUG != TRUE))
261 return true; // Disable using network sockets for security reasons
262 #endif
263
264 assert(listen_socket_ == NULL);
265 assert(thread_ == NULL);
266 assert(clients_ == NULL);
267
268 clients_ = list_new(client_free);
269 if (!clients_) {
270 LOG_ERROR("%s unable to create counter clients list", __func__);
271 goto error;
272 }
273
274 thread_ = thread_new("counter_socket");
275 if (!thread_) {
276 LOG_ERROR("%s unable to create counter thread", __func__);
277 goto error;
278 }
279
280 listen_socket_ = socket_new();
281 if (!listen_socket_) {
282 LOG_ERROR("%s unable to create listen socket", __func__);
283 goto error;
284 }
285
286 if (!socket_listen(listen_socket_, LISTEN_PORT)) {
287 LOG_ERROR("%s unable to setup listen socket", __func__);
288 goto error;
289 }
290
291 LOG_INFO("%s opened counter server socket", __func__);
292 socket_register(listen_socket_, thread_get_reactor(thread_), NULL, accept_ready, NULL);
293 return true;
294
295 error:;
296 counter_socket_close();
297 return false;
298 }
299
counter_socket_close(void)300 static void counter_socket_close(void) {
301 #if (!defined(BT_NET_DEBUG) || (BT_NET_DEBUG != TRUE))
302 return; // Disable using network sockets for security reasons
303 #endif
304
305 socket_free(listen_socket_);
306 thread_free(thread_);
307 list_free(clients_);
308
309 listen_socket_ = NULL;
310 thread_ = NULL;
311 clients_ = NULL;
312
313 LOG_INFO("%s closed counter server socket", __func__);
314 }
315
monitor_counter_iter_cb(const char * name,counter_data_t val,void * context)316 static bool monitor_counter_iter_cb(const char *name, counter_data_t val, void *context) {
317 socket_t *socket = (socket_t *)context;
318 output(socket, "counter:%s val:%lld\n", name, val);
319 return true;
320 }
321
client_free(void * ptr)322 static void client_free(void *ptr) {
323 if (!ptr)
324 return;
325
326 client_t *client = (client_t *)ptr;
327 socket_free(client->socket);
328 osi_free(client);
329 }
330
accept_ready(socket_t * socket,UNUSED_ATTR void * context)331 static void accept_ready(socket_t *socket, UNUSED_ATTR void *context) {
332 assert(socket != NULL);
333 assert(socket == listen_socket_);
334
335 LOG_INFO("%s accepted OSI monitor socket", __func__);
336 socket = socket_accept(socket);
337 if (!socket)
338 return;
339
340 client_t *client = (client_t *)osi_calloc(sizeof(client_t));
341 if (!client) {
342 LOG_ERROR("%s unable to allocate memory for client", __func__);
343 socket_free(socket);
344 return;
345 }
346
347 client->socket = socket;
348
349 if (!list_append(clients_, client)) {
350 LOG_ERROR("%s unable to add client to list", __func__);
351 client_free(client);
352 return;
353 }
354
355 socket_register(socket, thread_get_reactor(thread_), client, read_ready, NULL);
356
357 output(socket, WELCOME);
358 output(socket, PROMPT);
359 }
360
read_ready(socket_t * socket,void * context)361 static void read_ready(socket_t *socket, void *context) {
362 assert(socket != NULL);
363
364 client_t *client = (client_t *)context;
365
366 ssize_t ret = socket_read(socket, client->buffer + client->buffer_size, sizeof(client->buffer) - client->buffer_size);
367 if (ret == 0 || (ret == -1 && ret != EWOULDBLOCK && ret != EAGAIN)) {
368 list_remove(clients_, client);
369 return;
370 }
371
372 // Replace newline with end of string termination
373 // TODO(cmanton) Need proper semantics
374 for (size_t i = ret - 1; i > 0; --i) {
375 if (client->buffer[i] < 16)
376 *(client->buffer + i) = 0;
377 else
378 break;
379 }
380
381 const command_t *command = find_command((const char *)client->buffer);
382 if (!command) {
383 output(socket, "unable to find command %s\n", client->buffer);
384 } else {
385 int rc = command->handler(socket);
386 if (rc == 1) {
387 output(socket, GOODBYE);
388 socket_free(socket);
389 return;
390 }
391 }
392 output(socket, PROMPT);
393 }
394
output(socket_t * socket,const char * format,...)395 static void output(socket_t *socket, const char* format, ...) {
396 char dest[4096];
397 va_list argptr;
398 va_start(argptr, format);
399 vsprintf(dest, format, argptr);
400 va_end(argptr);
401 socket_write(socket, dest, strlen(dest));
402 }
403
help(UNUSED_ATTR socket_t * socket)404 static int help(UNUSED_ATTR socket_t *socket) {
405 output(socket, "help command unimplemented\n");
406 return 0;
407 }
408
quit(UNUSED_ATTR socket_t * socket)409 static int quit(UNUSED_ATTR socket_t *socket) {
410 return 1;
411 }
412
set(UNUSED_ATTR socket_t * socket)413 static int set(UNUSED_ATTR socket_t *socket) {
414 output(socket, "set command unimplemented\n");
415 return 0;
416 }
417
show(socket_t * socket)418 static int show(socket_t *socket) {
419 output(socket, "counter count registered:%d\n", counter_cnt_);
420 counter_foreach(monitor_counter_iter_cb, (void *)socket);
421 return 0;
422 }
423
find_command(const char * name)424 static const command_t *find_command(const char *name) {
425 for (size_t i = 0; i < ARRAY_SIZE(commands); ++i)
426 if (!strcmp(commands[i].name, name))
427 return &commands[i];
428 return NULL;
429 }
430