2072ac1109ec45fe2494448ae771973d9cc7236a
[platform/upstream/buxton.git] / src / shared / protocol.c
1 /*
2  * This file is part of buxton.
3  *
4  * Copyright (C) 2013 Intel Corporation
5  *
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.
10  */
11
12 #ifdef HAVE_CONFIG_H
13         #include "config.h"
14 #endif
15
16 #include <assert.h>
17 #include <errno.h>
18 #include <poll.h>
19 #include <pthread.h>
20 #include <stdlib.h>
21 #include <sys/time.h>
22
23 #include "buxtonclient.h"
24 #include "buxtonkey.h"
25 #include "buxtonresponse.h"
26 #include "buxtonstring.h"
27 #include "hashmap.h"
28 #include "log.h"
29 #include "protocol.h"
30 #include "util.h"
31
32 #define TIMEOUT 3
33
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;
38
39 struct notify_value {
40         void *data;
41         BuxtonCallback cb;
42         struct timeval tv;
43         BuxtonControlMessage type;
44         _BuxtonKey *key;
45 };
46
47 static uint32_t get_msgid(void)
48 {
49         return __sync_fetch_and_add(&_msgid, 1);
50 }
51
52 bool setup_callbacks(void)
53 {
54         bool r = false;
55         int s;
56
57         s = pthread_mutex_lock(&callback_guard);
58         if (s) {
59                 return false;
60         }
61
62         if (callbacks && notify_callbacks) {
63                 goto unlock;
64         }
65
66         callbacks = hashmap_new(trivial_hash_func, trivial_compare_func);
67         if (!callbacks) {
68                 goto unlock;
69         }
70
71         notify_callbacks = hashmap_new(trivial_hash_func, trivial_compare_func);
72         if (!notify_callbacks) {
73                 hashmap_free(callbacks);
74                 goto unlock;
75         }
76
77         r = true;
78
79 unlock:
80         s = pthread_mutex_unlock(&callback_guard);
81         if (s) {
82                 return false;
83         }
84
85         return r;
86 }
87
88 void cleanup_callbacks(void)
89 {
90         (void)pthread_mutex_lock(&callback_guard);
91
92         if (callbacks) {
93                 hashmap_free(callbacks);
94         }
95         callbacks = NULL;
96
97         if (notify_callbacks) {
98                 hashmap_free(notify_callbacks);
99         }
100         notify_callbacks = NULL;
101
102         (void)pthread_mutex_unlock(&callback_guard);
103 }
104
105 void run_callback(BuxtonCallback callback, void *data, size_t count,
106                   BuxtonData *list, BuxtonControlMessage type, _BuxtonKey *key)
107 {
108         BuxtonArray *array = NULL;
109         _BuxtonResponse response;
110
111         if (!callback) {
112                 goto out;
113         }
114
115         array = buxton_array_new();
116         if (!array) {
117                 goto out;
118         }
119
120         for (int i = 0; i < count; i++)
121                 if (!buxton_array_add(array, &list[i])) {
122                         goto out;
123                 }
124
125         response.type = type;
126         response.data = array;
127         response.key = key;
128         callback(&response, data);
129
130 out:
131         buxton_array_free(&array, NULL);
132 }
133
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)
137 {
138         struct notify_value *nv, *nvi;
139         _BuxtonKey *k = NULL;
140         int s;
141         bool r = false;
142         Iterator it;
143 #if UINTPTR_MAX == 0xffffffffffffffff
144         uint64_t hkey;
145 #else
146         uint32_t hkey;
147 #endif
148
149         nv = malloc0(sizeof(struct notify_value));
150         if (!nv) {
151                 goto fail;
152         }
153
154         if (key) {
155                 k = malloc0(sizeof(_BuxtonKey));
156                 if (!k) {
157                         goto fail;
158                 }
159                 if (!buxton_key_copy(key, k)) {
160                         goto fail;
161                 }
162         }
163
164         (void)gettimeofday(&nv->tv, NULL);
165         nv->cb = callback;
166         nv->data = data;
167         nv->type = type;
168         nv->key = k;
169
170         s = pthread_mutex_lock(&callback_guard);
171         if (s) {
172                 goto fail;
173         }
174
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);
179                         free(nvi);
180                 }
181         }
182
183 #if UINTPTR_MAX == 0xffffffffffffffff
184         s = hashmap_put(callbacks, (void *)((uint64_t)msgid), nv);
185 #else
186         s = hashmap_put(callbacks, (void *)msgid, nv);
187 #endif
188         (void)pthread_mutex_unlock(&callback_guard);
189
190         if (s < 1) {
191                 buxton_debug("Error adding callback for msgid: %llu\n", msgid);
192                 goto fail;
193         }
194
195         /* Now write it off */
196         if (!_write(client->fd, send, send_len)) {
197                 buxton_debug("Write failed for msgid: %llu\n", msgid);
198                 r = false;
199         } else {
200                 r = true;
201         }
202
203         return r;
204
205 fail:
206         free(nv);
207         key_free(k);
208         return false;
209 }
210
211 void handle_callback_response(BuxtonControlMessage msg, uint32_t msgid,
212                               BuxtonData *list, size_t count)
213 {
214         struct notify_value *nv;
215
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));
220 #else
221                 nv = hashmap_get(notify_callbacks, (void *)msgid);
222 #endif
223                 if (!nv) {
224                         return;
225                 }
226
227                 run_callback((BuxtonCallback)(nv->cb), nv->data, count, list,
228                              BUXTON_CONTROL_CHANGED, nv->key);
229                 return;
230         }
231
232 #if UINTPTR_MAX == 0xffffffffffffffff
233                 nv = hashmap_remove(callbacks, (void *)((uint64_t)msgid));
234 #else
235                 nv = hashmap_remove(callbacks, (void *)msgid);
236 #endif
237         if (!nv) {
238                 return;
239         }
240
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)
246 #else
247                         if (hashmap_put(notify_callbacks, (void *)msgid, nv)
248 #endif
249                             >= 0) {
250                                 return;
251                         }
252                 }
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));
259 #else
260                                              (void *)list[2].store.d_uint32);
261 #endif
262
263                         return;
264                 }
265         }
266
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,
270                      nv->key);
271
272         key_free(nv->key);
273         free(nv);
274 }
275
276 ssize_t buxton_wire_handle_response(_BuxtonClient *client)
277 {
278         ssize_t l;
279         _cleanup_free_ uint8_t *response = NULL;
280         BuxtonData *r_list = NULL;
281         BuxtonControlMessage r_msg = BUXTON_CONTROL_MIN;
282         ssize_t count = 0;
283         size_t offset = 0;
284         size_t size = BUXTON_MESSAGE_HEADER_LENGTH;
285         uint32_t r_msgid;
286         int s;
287         ssize_t handled = 0;
288
289         response = malloc0(BUXTON_MESSAGE_HEADER_LENGTH);
290         if (!response) {
291                 return 0;
292         }
293
294         do {
295                 l = read(client->fd, response + offset, size - offset);
296                 if (l <= 0) {
297                         return handled;
298                 }
299                 offset += (size_t)l;
300                 if (offset < BUXTON_MESSAGE_HEADER_LENGTH) {
301                         continue;
302                 }
303                 if (size == BUXTON_MESSAGE_HEADER_LENGTH) {
304                         size = buxton_get_message_size(response, offset);
305                         if (size == 0 || size > BUXTON_MESSAGE_MAX_LENGTH) {
306                                 return -1;
307                         }
308                 }
309                 if (size != BUXTON_MESSAGE_HEADER_LENGTH) {
310                         response = realloc(response, size);
311                         if (!response) {
312                                 return -1;
313                         }
314                 }
315                 if (size != offset) {
316                         continue;
317                 }
318
319                 count = buxton_deserialize_message(response, &r_msg, size, &r_msgid, &r_list);
320                 if (count < 0) {
321                         goto next;
322                 }
323
324                 if (!(r_msg == BUXTON_CONTROL_STATUS && r_list && r_list[0].type == INT32)
325                     && !(r_msg == BUXTON_CONTROL_CHANGED)) {
326                         handled++;
327                         buxton_log("Critical error: Invalid response\n");
328                         goto next;
329                 }
330
331                 s = pthread_mutex_lock(&callback_guard);
332                 if (s) {
333                         goto next;
334                 }
335
336                 handle_callback_response(r_msg, r_msgid, r_list, (size_t)count);
337
338                 (void)pthread_mutex_unlock(&callback_guard);
339                 handled++;
340
341         next:
342                 if (r_list) {
343                         for (int i = 0; i < count; i++) {
344                                 if (r_list[i].type == STRING) {
345                                         free(r_list[i].store.d_string.value);
346                                 }
347                         }
348                         free(r_list);
349                 }
350
351                 /* reset for next possible message */
352                 size = BUXTON_MESSAGE_HEADER_LENGTH;
353                 offset = 0;
354         } while (true);
355 }
356
357 int buxton_wire_get_response(_BuxtonClient *client)
358 {
359         struct pollfd pfd[1];
360         int r;
361         ssize_t processed;
362
363         pfd[0].fd = client->fd;
364         pfd[0].events = POLLIN;
365         pfd[0].revents = 0;
366         r = poll(pfd, 1, 5000);
367
368         if (r == 0) {
369                 return -ETIME;
370         } else if (r < 0) {
371                 return -errno;
372         }
373
374         processed = buxton_wire_handle_response(client);
375
376         return (int)processed;
377 }
378
379 bool buxton_wire_set_value(_BuxtonClient *client, _BuxtonKey *key, void *value,
380                            BuxtonCallback callback, void *data)
381 {
382         _cleanup_free_ uint8_t *send = NULL;
383         bool ret = false;
384         size_t send_len = 0;
385         BuxtonArray *list = NULL;
386         BuxtonData d_layer;
387         BuxtonData d_group;
388         BuxtonData d_name;
389         BuxtonData d_value;
390         uint32_t msgid = get_msgid();
391
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;
396         switch (key->type) {
397         case STRING:
398                 d_value.store.d_string.value = (char *)value;
399                 d_value.store.d_string.length = (uint32_t)strlen((char *)value) + 1;
400                 break;
401         case INT32:
402                 d_value.store.d_int32 = *(int32_t *)value;
403                 break;
404         case INT64:
405                 d_value.store.d_int64 = *(int64_t *)value;
406                 break;
407         case UINT32:
408                 d_value.store.d_uint32 = *(uint32_t *)value;
409                 break;
410         case UINT64:
411                 d_value.store.d_uint64 = *(uint64_t *)value;
412                 break;
413         case FLOAT:
414                 d_value.store.d_float = *(float *)value;
415                 break;
416         case DOUBLE:
417                 d_value.store.d_double = *(double *)value;
418                 break;
419         case BOOLEAN:
420                 d_value.store.d_boolean = *(bool *)value;
421                 break;
422         default:
423                 break;
424         }
425
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");
429                 goto end;
430         }
431         if (!buxton_array_add(list, &d_group)) {
432                 buxton_log("Failed to add group to set_value array\n");
433                 goto end;
434         }
435         if (!buxton_array_add(list, &d_name)) {
436                 buxton_log("Failed to add name to set_value array\n");
437                 goto end;
438         }
439         if (!buxton_array_add(list, &d_value)) {
440                 buxton_log("Failed to add value to set_value array\n");
441                 goto end;
442         }
443
444         send_len = buxton_serialize_message(&send, BUXTON_CONTROL_SET, msgid, list);
445
446         if (send_len == 0) {
447                 goto end;
448         }
449
450
451         if (!send_message(client, send, send_len, callback, data, msgid,
452                           BUXTON_CONTROL_SET, key)) {
453                 goto end;
454         }
455
456         ret = true;
457
458 end:
459         buxton_array_free(&list, NULL);
460         return ret;
461 }
462
463 bool buxton_wire_set_label(_BuxtonClient *client,
464                            _BuxtonKey *key, BuxtonString *value,
465                            BuxtonCallback callback, void *data)
466 {
467         assert(client);
468         assert(key);
469         assert(value);
470
471         _cleanup_free_ uint8_t *send = NULL;
472         bool ret = false;
473         size_t send_len = 0;
474         BuxtonArray *list = NULL;
475         BuxtonData d_layer;
476         BuxtonData d_group;
477         BuxtonData d_name;
478         BuxtonData d_value;
479         uint32_t msgid = get_msgid();
480
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);
484
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");
488                 goto end;
489         }
490         if (!buxton_array_add(list, &d_group)) {
491                 buxton_log("Failed to add group to set_label array\n");
492                 goto end;
493         }
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");
498                         goto end;
499                 }
500         }
501         if (!buxton_array_add(list, &d_value)) {
502                 buxton_log("Failed to add value to set_label array\n");
503                 goto end;
504         }
505
506         send_len = buxton_serialize_message(&send, BUXTON_CONTROL_SET_LABEL, msgid, list);
507
508         if (send_len == 0) {
509                 goto end;
510         }
511
512         if (!send_message(client, send, send_len, callback, data, msgid,
513                           BUXTON_CONTROL_SET_LABEL, key)) {
514                 goto end;
515         }
516
517         ret = true;
518
519 end:
520         buxton_array_free(&list, NULL);
521         return ret;
522 }
523
524 bool buxton_wire_create_group(_BuxtonClient *client, _BuxtonKey *key,
525                               BuxtonCallback callback, void *data)
526 {
527         assert(client);
528         assert(key);
529
530         _cleanup_free_ uint8_t *send = NULL;
531         bool ret = false;
532         size_t send_len = 0;
533         BuxtonArray *list = NULL;
534         BuxtonData d_layer;
535         BuxtonData d_group;
536         uint32_t msgid = get_msgid();
537
538         buxton_string_to_data(&key->layer, &d_layer);
539         buxton_string_to_data(&key->group, &d_group);
540
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");
544                 goto end;
545         }
546         if (!buxton_array_add(list, &d_group)) {
547                 buxton_log("Failed to add group to create_group array\n");
548                 goto end;
549         }
550
551         send_len = buxton_serialize_message(&send, BUXTON_CONTROL_CREATE_GROUP, msgid, list);
552
553         if (send_len == 0) {
554                 goto end;
555         }
556
557         if (!send_message(client, send, send_len, callback, data, msgid,
558                           BUXTON_CONTROL_CREATE_GROUP, key)) {
559                 goto end;
560         }
561
562         ret = true;
563
564 end:
565         buxton_array_free(&list, NULL);
566         return ret;
567 }
568
569 bool buxton_wire_remove_group(_BuxtonClient *client, _BuxtonKey *key,
570                               BuxtonCallback callback, void *data)
571 {
572         assert(client);
573         assert(key);
574
575         _cleanup_free_ uint8_t *send = NULL;
576         bool ret = false;
577         size_t send_len = 0;
578         BuxtonArray *list = NULL;
579         BuxtonData d_layer;
580         BuxtonData d_group;
581         uint32_t msgid = get_msgid();
582
583         buxton_string_to_data(&key->layer, &d_layer);
584         buxton_string_to_data(&key->group, &d_group);
585
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");
589                 goto end;
590         }
591         if (!buxton_array_add(list, &d_group)) {
592                 buxton_log("Failed to add group to remove_group array\n");
593                 goto end;
594         }
595
596         send_len = buxton_serialize_message(&send, BUXTON_CONTROL_REMOVE_GROUP, msgid, list);
597
598         if (send_len == 0) {
599                 goto end;
600         }
601
602         if (!send_message(client, send, send_len, callback, data, msgid,
603                           BUXTON_CONTROL_REMOVE_GROUP, key)) {
604                 goto end;
605         }
606
607         ret = true;
608
609 end:
610         buxton_array_free(&list, NULL);
611         return ret;
612 }
613
614 bool buxton_wire_get_value(_BuxtonClient *client, _BuxtonKey *key,
615                            BuxtonCallback callback, void *data)
616 {
617         bool ret = false;
618         size_t send_len = 0;
619         _cleanup_free_ uint8_t *send = NULL;
620         BuxtonArray *list = NULL;
621         BuxtonData d_layer;
622         BuxtonData d_group;
623         BuxtonData d_name;
624         BuxtonData d_type;
625         uint32_t msgid = get_msgid();
626
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;
631
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");
637                         goto end;
638                 }
639         }
640         if (!buxton_array_add(list, &d_group)) {
641                 buxton_log("Failed to add group to set_value array\n");
642                 goto end;
643         }
644         if (!buxton_array_add(list, &d_name)) {
645                 buxton_log("Failed to add name to set_value array\n");
646                 goto end;
647         }
648         if (!buxton_array_add(list, &d_type)) {
649                 buxton_log("Failed to add type to set_value array\n");
650                 goto end;
651         }
652
653         send_len = buxton_serialize_message(&send, BUXTON_CONTROL_GET, msgid, list);
654
655         if (send_len == 0) {
656                 goto end;
657         }
658
659         if (!send_message(client, send, send_len, callback, data, msgid,
660                           BUXTON_CONTROL_GET, key)) {
661                 goto end;
662         }
663
664         ret = true;
665
666 end:
667         buxton_array_free(&list, NULL);
668         return ret;
669 }
670
671 bool buxton_wire_unset_value(_BuxtonClient *client,
672                              _BuxtonKey *key,
673                              BuxtonCallback callback,
674                              void *data)
675 {
676         assert(client);
677         assert(key);
678
679         _cleanup_free_ uint8_t *send = NULL;
680         size_t send_len = 0;
681         BuxtonArray *list = NULL;
682         BuxtonData d_group;
683         BuxtonData d_name;
684         BuxtonData d_layer;
685         BuxtonData d_type;
686         bool ret = false;
687         uint32_t msgid = get_msgid();
688
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;
694
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");
698                 goto end;
699         }
700         if (!buxton_array_add(list, &d_group)) {
701                 buxton_log("Failed to add group to set_value array\n");
702                 goto end;
703         }
704         if (!buxton_array_add(list, &d_name)) {
705                 buxton_log("Failed to add name to set_value array\n");
706                 goto end;
707         }
708         if (!buxton_array_add(list, &d_type)) {
709                 buxton_log("Failed to add type to set_value array\n");
710                 goto end;
711         }
712
713         send_len = buxton_serialize_message(&send, BUXTON_CONTROL_UNSET,
714                                             msgid, list);
715
716         if (send_len == 0) {
717                 goto end;
718         }
719
720         if (!send_message(client, send, send_len, callback, data, msgid,
721                           BUXTON_CONTROL_UNSET, key)) {
722                 goto end;
723         }
724
725         ret = true;
726
727 end:
728         buxton_array_free(&list, NULL);
729         return ret;
730 }
731
732 bool buxton_wire_list_keys(_BuxtonClient *client,
733                            BuxtonString *layer,
734                            BuxtonCallback callback,
735                            void *data)
736 {
737         assert(client);
738         assert(layer);
739
740         _cleanup_free_ uint8_t *send = NULL;
741         size_t send_len = 0;
742         BuxtonArray *list = NULL;
743         BuxtonData d_layer;
744         bool ret = false;
745         uint32_t msgid = get_msgid();
746
747         buxton_string_to_data(layer, &d_layer);
748
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");
752                 goto end;
753         }
754
755         send_len = buxton_serialize_message(&send, BUXTON_CONTROL_LIST, msgid,
756                                             list);
757
758         if (send_len == 0) {
759                 goto end;
760         }
761
762         if (!send_message(client, send, send_len, callback, data, msgid,
763                           BUXTON_CONTROL_LIST, NULL)) {
764                 goto end;
765         }
766
767         ret = true;
768
769 end:
770         buxton_array_free(&list, NULL);
771
772         return ret;
773 }
774
775 bool buxton_wire_register_notification(_BuxtonClient *client,
776                                        _BuxtonKey *key,
777                                        BuxtonCallback callback,
778                                        void *data)
779 {
780         assert(client);
781         assert(key);
782
783         _cleanup_free_ uint8_t *send = NULL;
784         size_t send_len = 0;
785         BuxtonArray *list = NULL;
786         BuxtonData d_group;
787         BuxtonData d_name;
788         BuxtonData d_type;
789         bool ret = false;
790         uint32_t msgid = get_msgid();
791
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;
796
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");
800                 goto end;
801         }
802         if (!buxton_array_add(list, &d_name)) {
803                 buxton_log("Failed to add name to set_value array\n");
804                 goto end;
805         }
806         if (!buxton_array_add(list, &d_type)) {
807                 buxton_log("Failed to add type to set_value array\n");
808                 goto end;
809         }
810
811         send_len = buxton_serialize_message(&send, BUXTON_CONTROL_NOTIFY, msgid,
812                                             list);
813
814         if (send_len == 0) {
815                 goto end;
816         }
817
818         if (!send_message(client, send, send_len, callback, data, msgid,
819                           BUXTON_CONTROL_NOTIFY, key)) {
820                 goto end;
821         }
822
823         ret = true;
824
825 end:
826         buxton_array_free(&list, NULL);
827         return ret;
828 }
829
830 bool buxton_wire_unregister_notification(_BuxtonClient *client,
831                                          _BuxtonKey *key,
832                                          BuxtonCallback callback,
833                                          void *data)
834 {
835         assert(client);
836         assert(key);
837
838         _cleanup_free_ uint8_t *send = NULL;
839         size_t send_len = 0;
840         BuxtonArray *list = NULL;
841         BuxtonData d_group;
842         BuxtonData d_name;
843         BuxtonData d_type;
844         bool ret = false;
845         uint32_t msgid = get_msgid();
846
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;
851
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");
855                 goto end;
856         }
857         if (!buxton_array_add(list, &d_name)) {
858                 buxton_log("Failed to add name to set_value array\n");
859                 goto end;
860         }
861         if (!buxton_array_add(list, &d_type)) {
862                 buxton_log("Failed to add type to set_value array\n");
863                 goto end;
864         }
865
866         send_len = buxton_serialize_message(&send, BUXTON_CONTROL_UNNOTIFY,
867                                             msgid, list);
868
869         if (send_len == 0) {
870                 goto end;
871         }
872
873         if (!send_message(client, send, send_len, callback, data, msgid,
874                           BUXTON_CONTROL_UNNOTIFY, key)) {
875                 goto end;
876         }
877
878         ret = true;
879
880 end:
881         buxton_array_free(&list, NULL);
882         return ret;
883 }
884
885 void include_protocol(void)
886 {
887         ;
888 }
889
890 /*
891  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
892  *
893  * Local variables:
894  * c-basic-offset: 8
895  * tab-width: 8
896  * indent-tabs-mode: t
897  * End:
898  *
899  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
900  * :indentSize=8:tabSize=8:noTabs=false:
901  */