• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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