2 * This file is part of buxton.
4 * Copyright (C) 2013 Intel Corporation
6 * buxton is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as
8 * published by the Free Software Foundation; either version 2.1
9 * of the License, or (at your option) any later version.
23 #include "buxtonclient.h"
24 #include "buxtonkey.h"
25 #include "buxtonresponse.h"
26 #include "buxtonstring.h"
34 static pthread_mutex_t callback_guard = PTHREAD_MUTEX_INITIALIZER;
35 static Hashmap *callbacks = NULL;
36 static Hashmap *notify_callbacks = NULL;
37 static volatile uint32_t _msgid = 0;
43 BuxtonControlMessage type;
47 static uint32_t get_msgid(void)
49 return __sync_fetch_and_add(&_msgid, 1);
52 bool setup_callbacks(void)
57 s = pthread_mutex_lock(&callback_guard);
62 if (callbacks && notify_callbacks) {
66 callbacks = hashmap_new(trivial_hash_func, trivial_compare_func);
71 notify_callbacks = hashmap_new(trivial_hash_func, trivial_compare_func);
72 if (!notify_callbacks) {
73 hashmap_free(callbacks);
80 s = pthread_mutex_unlock(&callback_guard);
88 void cleanup_callbacks(void)
90 (void)pthread_mutex_lock(&callback_guard);
93 hashmap_free(callbacks);
97 if (notify_callbacks) {
98 hashmap_free(notify_callbacks);
100 notify_callbacks = NULL;
102 (void)pthread_mutex_unlock(&callback_guard);
105 void run_callback(BuxtonCallback callback, void *data, size_t count,
106 BuxtonData *list, BuxtonControlMessage type, _BuxtonKey *key)
108 BuxtonArray *array = NULL;
109 _BuxtonResponse response;
115 array = buxton_array_new();
120 for (int i = 0; i < count; i++)
121 if (!buxton_array_add(array, &list[i])) {
125 response.type = type;
126 response.data = array;
128 callback(&response, data);
131 buxton_array_free(&array, NULL);
134 bool send_message(_BuxtonClient *client, uint8_t *send, size_t send_len,
135 BuxtonCallback callback, void *data, uint32_t msgid,
136 BuxtonControlMessage type, _BuxtonKey *key)
138 struct notify_value *nv, *nvi;
139 _BuxtonKey *k = NULL;
143 #if UINTPTR_MAX == 0xffffffffffffffff
149 nv = malloc0(sizeof(struct notify_value));
155 k = malloc0(sizeof(_BuxtonKey));
159 if (!buxton_key_copy(key, k)) {
164 (void)gettimeofday(&nv->tv, NULL);
170 s = pthread_mutex_lock(&callback_guard);
175 /* remove timed out callbacks */
176 HASHMAP_FOREACH_KEY(nvi, hkey, callbacks, it) {
177 if (nv->tv.tv_sec - nvi->tv.tv_sec > TIMEOUT) {
178 (void)hashmap_remove(callbacks, (void *)hkey);
183 #if UINTPTR_MAX == 0xffffffffffffffff
184 s = hashmap_put(callbacks, (void *)((uint64_t)msgid), nv);
186 s = hashmap_put(callbacks, (void *)msgid, nv);
188 (void)pthread_mutex_unlock(&callback_guard);
191 buxton_debug("Error adding callback for msgid: %llu\n", msgid);
195 /* Now write it off */
196 if (!_write(client->fd, send, send_len)) {
197 buxton_debug("Write failed for msgid: %llu\n", msgid);
211 void handle_callback_response(BuxtonControlMessage msg, uint32_t msgid,
212 BuxtonData *list, size_t count)
214 struct notify_value *nv;
216 /* use notification callbacks for notification messages */
217 if (msg == BUXTON_CONTROL_CHANGED) {
218 #if UINTPTR_MAX == 0xffffffffffffffff
219 nv = hashmap_get(notify_callbacks, (void *)((uint64_t)msgid));
221 nv = hashmap_get(notify_callbacks, (void *)msgid);
227 run_callback((BuxtonCallback)(nv->cb), nv->data, count, list,
228 BUXTON_CONTROL_CHANGED, nv->key);
232 #if UINTPTR_MAX == 0xffffffffffffffff
233 nv = hashmap_remove(callbacks, (void *)((uint64_t)msgid));
235 nv = hashmap_remove(callbacks, (void *)msgid);
241 if (nv->type == BUXTON_CONTROL_NOTIFY) {
242 if (list[0].type == INT32 &&
243 list[0].store.d_int32 == 0) {
244 #if UINTPTR_MAX == 0xffffffffffffffff
245 if (hashmap_put(notify_callbacks, (void *)((uint64_t)msgid), nv)
247 if (hashmap_put(notify_callbacks, (void *)msgid, nv)
253 } else if (nv->type == BUXTON_CONTROL_UNNOTIFY) {
254 if (list[0].type == INT32 &&
255 list[0].store.d_int32 == 0) {
256 (void)hashmap_remove(notify_callbacks,
257 #if UINTPTR_MAX == 0xffffffffffffffff
258 (void *)((uint64_t)list[2].store.d_uint32));
260 (void *)list[2].store.d_uint32);
267 /* callback should be run on notfiy or unnotify failure */
268 /* and on any other server message we are waiting for */
269 run_callback((BuxtonCallback)(nv->cb), nv->data, count, list, nv->type,
276 ssize_t buxton_wire_handle_response(_BuxtonClient *client)
279 _cleanup_free_ uint8_t *response = NULL;
280 BuxtonData *r_list = NULL;
281 BuxtonControlMessage r_msg = BUXTON_CONTROL_MIN;
284 size_t size = BUXTON_MESSAGE_HEADER_LENGTH;
289 response = malloc0(BUXTON_MESSAGE_HEADER_LENGTH);
295 l = read(client->fd, response + offset, size - offset);
300 if (offset < BUXTON_MESSAGE_HEADER_LENGTH) {
303 if (size == BUXTON_MESSAGE_HEADER_LENGTH) {
304 size = buxton_get_message_size(response, offset);
305 if (size == 0 || size > BUXTON_MESSAGE_MAX_LENGTH) {
309 if (size != BUXTON_MESSAGE_HEADER_LENGTH) {
310 response = realloc(response, size);
315 if (size != offset) {
319 count = buxton_deserialize_message(response, &r_msg, size, &r_msgid, &r_list);
324 if (!(r_msg == BUXTON_CONTROL_STATUS && r_list && r_list[0].type == INT32)
325 && !(r_msg == BUXTON_CONTROL_CHANGED)) {
327 buxton_log("Critical error: Invalid response\n");
331 s = pthread_mutex_lock(&callback_guard);
336 handle_callback_response(r_msg, r_msgid, r_list, (size_t)count);
338 (void)pthread_mutex_unlock(&callback_guard);
343 for (int i = 0; i < count; i++) {
344 if (r_list[i].type == STRING) {
345 free(r_list[i].store.d_string.value);
351 /* reset for next possible message */
352 size = BUXTON_MESSAGE_HEADER_LENGTH;
357 int buxton_wire_get_response(_BuxtonClient *client)
359 struct pollfd pfd[1];
363 pfd[0].fd = client->fd;
364 pfd[0].events = POLLIN;
366 r = poll(pfd, 1, 5000);
374 processed = buxton_wire_handle_response(client);
376 return (int)processed;
379 bool buxton_wire_set_value(_BuxtonClient *client, _BuxtonKey *key, void *value,
380 BuxtonCallback callback, void *data)
382 _cleanup_free_ uint8_t *send = NULL;
385 BuxtonArray *list = NULL;
390 uint32_t msgid = get_msgid();
392 buxton_string_to_data(&key->layer, &d_layer);
393 buxton_string_to_data(&key->group, &d_group);
394 buxton_string_to_data(&key->name, &d_name);
395 d_value.type = key->type;
398 d_value.store.d_string.value = (char *)value;
399 d_value.store.d_string.length = (uint32_t)strlen((char *)value) + 1;
402 d_value.store.d_int32 = *(int32_t *)value;
405 d_value.store.d_int64 = *(int64_t *)value;
408 d_value.store.d_uint32 = *(uint32_t *)value;
411 d_value.store.d_uint64 = *(uint64_t *)value;
414 d_value.store.d_float = *(float *)value;
417 d_value.store.d_double = *(double *)value;
420 d_value.store.d_boolean = *(bool *)value;
426 list = buxton_array_new();
427 if (!buxton_array_add(list, &d_layer)) {
428 buxton_log("Failed to add layer to set_value array\n");
431 if (!buxton_array_add(list, &d_group)) {
432 buxton_log("Failed to add group to set_value array\n");
435 if (!buxton_array_add(list, &d_name)) {
436 buxton_log("Failed to add name to set_value array\n");
439 if (!buxton_array_add(list, &d_value)) {
440 buxton_log("Failed to add value to set_value array\n");
444 send_len = buxton_serialize_message(&send, BUXTON_CONTROL_SET, msgid, list);
451 if (!send_message(client, send, send_len, callback, data, msgid,
452 BUXTON_CONTROL_SET, key)) {
459 buxton_array_free(&list, NULL);
463 bool buxton_wire_set_label(_BuxtonClient *client,
464 _BuxtonKey *key, BuxtonString *value,
465 BuxtonCallback callback, void *data)
471 _cleanup_free_ uint8_t *send = NULL;
474 BuxtonArray *list = NULL;
479 uint32_t msgid = get_msgid();
481 buxton_string_to_data(&key->layer, &d_layer);
482 buxton_string_to_data(&key->group, &d_group);
483 buxton_string_to_data(value, &d_value);
485 list = buxton_array_new();
486 if (!buxton_array_add(list, &d_layer)) {
487 buxton_log("Failed to add layer to set_label array\n");
490 if (!buxton_array_add(list, &d_group)) {
491 buxton_log("Failed to add group to set_label array\n");
494 if (key->name.value) {
495 buxton_string_to_data(&key->name, &d_name);
496 if (!buxton_array_add(list, &d_name)) {
497 buxton_log("Failed to add name to set_label array\n");
501 if (!buxton_array_add(list, &d_value)) {
502 buxton_log("Failed to add value to set_label array\n");
506 send_len = buxton_serialize_message(&send, BUXTON_CONTROL_SET_LABEL, msgid, list);
512 if (!send_message(client, send, send_len, callback, data, msgid,
513 BUXTON_CONTROL_SET_LABEL, key)) {
520 buxton_array_free(&list, NULL);
524 bool buxton_wire_create_group(_BuxtonClient *client, _BuxtonKey *key,
525 BuxtonCallback callback, void *data)
530 _cleanup_free_ uint8_t *send = NULL;
533 BuxtonArray *list = NULL;
536 uint32_t msgid = get_msgid();
538 buxton_string_to_data(&key->layer, &d_layer);
539 buxton_string_to_data(&key->group, &d_group);
541 list = buxton_array_new();
542 if (!buxton_array_add(list, &d_layer)) {
543 buxton_log("Failed to add layer to create_group array\n");
546 if (!buxton_array_add(list, &d_group)) {
547 buxton_log("Failed to add group to create_group array\n");
551 send_len = buxton_serialize_message(&send, BUXTON_CONTROL_CREATE_GROUP, msgid, list);
557 if (!send_message(client, send, send_len, callback, data, msgid,
558 BUXTON_CONTROL_CREATE_GROUP, key)) {
565 buxton_array_free(&list, NULL);
569 bool buxton_wire_remove_group(_BuxtonClient *client, _BuxtonKey *key,
570 BuxtonCallback callback, void *data)
575 _cleanup_free_ uint8_t *send = NULL;
578 BuxtonArray *list = NULL;
581 uint32_t msgid = get_msgid();
583 buxton_string_to_data(&key->layer, &d_layer);
584 buxton_string_to_data(&key->group, &d_group);
586 list = buxton_array_new();
587 if (!buxton_array_add(list, &d_layer)) {
588 buxton_log("Failed to add layer to remove_group array\n");
591 if (!buxton_array_add(list, &d_group)) {
592 buxton_log("Failed to add group to remove_group array\n");
596 send_len = buxton_serialize_message(&send, BUXTON_CONTROL_REMOVE_GROUP, msgid, list);
602 if (!send_message(client, send, send_len, callback, data, msgid,
603 BUXTON_CONTROL_REMOVE_GROUP, key)) {
610 buxton_array_free(&list, NULL);
614 bool buxton_wire_get_value(_BuxtonClient *client, _BuxtonKey *key,
615 BuxtonCallback callback, void *data)
619 _cleanup_free_ uint8_t *send = NULL;
620 BuxtonArray *list = NULL;
625 uint32_t msgid = get_msgid();
627 buxton_string_to_data(&key->group, &d_group);
628 buxton_string_to_data(&key->name, &d_name);
629 d_type.type = UINT32;
630 d_type.store.d_int32 = key->type;
632 list = buxton_array_new();
633 if (key->layer.value) {
634 buxton_string_to_data(&key->layer, &d_layer);
635 if (!buxton_array_add(list, &d_layer)) {
636 buxton_log("Unable to prepare get_value message\n");
640 if (!buxton_array_add(list, &d_group)) {
641 buxton_log("Failed to add group to set_value array\n");
644 if (!buxton_array_add(list, &d_name)) {
645 buxton_log("Failed to add name to set_value array\n");
648 if (!buxton_array_add(list, &d_type)) {
649 buxton_log("Failed to add type to set_value array\n");
653 send_len = buxton_serialize_message(&send, BUXTON_CONTROL_GET, msgid, list);
659 if (!send_message(client, send, send_len, callback, data, msgid,
660 BUXTON_CONTROL_GET, key)) {
667 buxton_array_free(&list, NULL);
671 bool buxton_wire_unset_value(_BuxtonClient *client,
673 BuxtonCallback callback,
679 _cleanup_free_ uint8_t *send = NULL;
681 BuxtonArray *list = NULL;
687 uint32_t msgid = get_msgid();
689 buxton_string_to_data(&key->group, &d_group);
690 buxton_string_to_data(&key->name, &d_name);
691 buxton_string_to_data(&key->layer, &d_layer);
692 d_type.type = UINT32;
693 d_type.store.d_int32 = key->type;
695 list = buxton_array_new();
696 if (!buxton_array_add(list, &d_layer)) {
697 buxton_log("Failed to add layer to set_value array\n");
700 if (!buxton_array_add(list, &d_group)) {
701 buxton_log("Failed to add group to set_value array\n");
704 if (!buxton_array_add(list, &d_name)) {
705 buxton_log("Failed to add name to set_value array\n");
708 if (!buxton_array_add(list, &d_type)) {
709 buxton_log("Failed to add type to set_value array\n");
713 send_len = buxton_serialize_message(&send, BUXTON_CONTROL_UNSET,
720 if (!send_message(client, send, send_len, callback, data, msgid,
721 BUXTON_CONTROL_UNSET, key)) {
728 buxton_array_free(&list, NULL);
732 bool buxton_wire_list_keys(_BuxtonClient *client,
734 BuxtonCallback callback,
740 _cleanup_free_ uint8_t *send = NULL;
742 BuxtonArray *list = NULL;
745 uint32_t msgid = get_msgid();
747 buxton_string_to_data(layer, &d_layer);
749 list = buxton_array_new();
750 if (!buxton_array_add(list, &d_layer)) {
751 buxton_log("Unable to add layer to list_keys array\n");
755 send_len = buxton_serialize_message(&send, BUXTON_CONTROL_LIST, msgid,
762 if (!send_message(client, send, send_len, callback, data, msgid,
763 BUXTON_CONTROL_LIST, NULL)) {
770 buxton_array_free(&list, NULL);
775 bool buxton_wire_register_notification(_BuxtonClient *client,
777 BuxtonCallback callback,
783 _cleanup_free_ uint8_t *send = NULL;
785 BuxtonArray *list = NULL;
790 uint32_t msgid = get_msgid();
792 buxton_string_to_data(&key->group, &d_group);
793 buxton_string_to_data(&key->name, &d_name);
794 d_type.type = UINT32;
795 d_type.store.d_int32 = key->type;
797 list = buxton_array_new();
798 if (!buxton_array_add(list, &d_group)) {
799 buxton_log("Failed to add group to set_value array\n");
802 if (!buxton_array_add(list, &d_name)) {
803 buxton_log("Failed to add name to set_value array\n");
806 if (!buxton_array_add(list, &d_type)) {
807 buxton_log("Failed to add type to set_value array\n");
811 send_len = buxton_serialize_message(&send, BUXTON_CONTROL_NOTIFY, msgid,
818 if (!send_message(client, send, send_len, callback, data, msgid,
819 BUXTON_CONTROL_NOTIFY, key)) {
826 buxton_array_free(&list, NULL);
830 bool buxton_wire_unregister_notification(_BuxtonClient *client,
832 BuxtonCallback callback,
838 _cleanup_free_ uint8_t *send = NULL;
840 BuxtonArray *list = NULL;
845 uint32_t msgid = get_msgid();
847 buxton_string_to_data(&key->group, &d_group);
848 buxton_string_to_data(&key->name, &d_name);
849 d_type.type = UINT32;
850 d_type.store.d_int32 = key->type;
852 list = buxton_array_new();
853 if (!buxton_array_add(list, &d_group)) {
854 buxton_log("Failed to add group to set_value array\n");
857 if (!buxton_array_add(list, &d_name)) {
858 buxton_log("Failed to add name to set_value array\n");
861 if (!buxton_array_add(list, &d_type)) {
862 buxton_log("Failed to add type to set_value array\n");
866 send_len = buxton_serialize_message(&send, BUXTON_CONTROL_UNNOTIFY,
873 if (!send_message(client, send, send_len, callback, data, msgid,
874 BUXTON_CONTROL_UNNOTIFY, key)) {
881 buxton_array_free(&list, NULL);
885 void include_protocol(void)
891 * Editor modelines - http://www.wireshark.org/tools/modelines.html
896 * indent-tabs-mode: t
899 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
900 * :indentSize=8:tabSize=8:noTabs=false: