tizen 2.3 release
[external/buxton.git] / src / libbuxton / lbuxton.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 /**
13  * \file lbuxton.c Buxton library implementation
14  */
15 #ifdef HAVE_CONFIG_H
16         #include "config.h"
17 #endif
18
19 #include <assert.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <unistd.h>
25 #include <sys/socket.h>
26 #include <sys/stat.h>
27 #include <sys/types.h>
28 #include <sys/un.h>
29 #include <dirent.h>
30 #include <string.h>
31 #include <stdint.h>
32
33 #include "buxton.h"
34 #include "buxtonclient.h"
35 #include "buxtonkey.h"
36 #include "buxtonresponse.h"
37 #include "buxtonstring.h"
38 #include "configurator.h"
39 #include "hashmap.h"
40 #include "log.h"
41 #include "protocol.h"
42 #include "util.h"
43
44 static Hashmap *key_hash = NULL;
45
46 int buxton_set_conf_file(char *path)
47 {
48         int r;
49         struct stat st;
50
51         r = stat(path, &st);
52         if (r == -1) {
53                 return errno;
54         } else {
55                 if (st.st_mode & S_IFDIR) {
56                         return EINVAL;
57                 }
58         }
59
60         buxton_add_cmd_line(CONFIG_CONF_FILE, path);
61
62         return 0;
63 }
64
65 int buxton_open(BuxtonClient *client)
66 {
67         _BuxtonClient **c = (_BuxtonClient **)client;
68         _BuxtonClient *cl = NULL;
69         int bx_socket, r;
70         struct sockaddr_un remote;
71         size_t sock_name_len;
72
73         if ((bx_socket = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
74                 return -1;
75         }
76
77         remote.sun_family = AF_UNIX;
78         sock_name_len = strlen(buxton_socket()) + 1;
79         if (sock_name_len >= sizeof(remote.sun_path)) {
80                 buxton_log("Provided socket name: %s is too long, maximum allowed length is %d bytes\n",
81                            buxton_socket(), sizeof(remote.sun_path));
82                 return -1;
83         }
84
85         strncpy(remote.sun_path, buxton_socket(), sock_name_len);
86         r = connect(bx_socket, (struct sockaddr *)&remote, sizeof(remote));
87         if ( r == -1) {
88                 close(bx_socket);
89                 return -1;
90         }
91
92         if (fcntl(bx_socket, F_SETFL, O_NONBLOCK)) {
93                 close(bx_socket);
94                 return -1;
95         }
96
97         if (!setup_callbacks()) {
98                 close(bx_socket);
99                 return -1;
100         }
101
102         cl = malloc0(sizeof(_BuxtonClient));
103         if (!cl) {
104                 close(bx_socket);
105                 return -1;
106         }
107
108         cl->fd = bx_socket;
109         *c = cl;
110
111         return bx_socket;
112 }
113
114 void buxton_close(BuxtonClient client)
115 {
116         _BuxtonClient *c;
117         BuxtonKey key = NULL;
118         Iterator i;
119
120         /* Free all remaining allocated keys */
121         HASHMAP_FOREACH_KEY(key, key, key_hash, i) {
122                 hashmap_remove_value(key_hash, key, key);
123                 buxton_key_free(key);
124         }
125
126         hashmap_free(key_hash);
127
128         if (!client) {
129                 return;
130         }
131
132         c = (_BuxtonClient *)client;
133
134         cleanup_callbacks();
135         close(c->fd);
136         c->direct = 0;
137         c->fd = -1;
138         free(c);
139 }
140
141 int buxton_get_value(BuxtonClient client,
142                      BuxtonKey key,
143                      BuxtonCallback callback,
144                      void *data,
145                      bool sync)
146 {
147         bool r;
148         int ret = 0;
149         _BuxtonKey *k = (_BuxtonKey *)key;
150
151         if (!k || !(k->group.value) || !(k->name.value) ||
152             k->type <= BUXTON_TYPE_MIN || k->type >= BUXTON_TYPE_MAX) {
153                 return EINVAL;
154         }
155
156         r = buxton_wire_get_value((_BuxtonClient *)client, k, callback, data);
157         if (!r) {
158                 return -1;
159         }
160
161         if (sync) {
162                 ret = buxton_wire_get_response(client);
163                 if (ret <= 0) {
164                         ret = -1;
165                 } else {
166                         ret = 0;
167                 }
168         }
169
170         return ret;
171 }
172
173 int buxton_register_notification(BuxtonClient client,
174                                  BuxtonKey key,
175                                  BuxtonCallback callback,
176                                  void *data,
177                                  bool sync)
178 {
179         bool r;
180         int ret = 0;
181         _BuxtonKey *k = (_BuxtonKey *)key;
182
183         if (!k || !k->group.value || !k->name.value ||
184             k->type <= BUXTON_TYPE_MIN || k->type >= BUXTON_TYPE_MAX) {
185                 return EINVAL;
186         }
187
188         r = buxton_wire_register_notification((_BuxtonClient *)client, k,
189                                               callback, data);
190         if (!r) {
191                 return -1;
192         }
193
194         if (sync) {
195                 ret = buxton_wire_get_response(client);
196                 if (ret <= 0) {
197                         ret = -1;
198                 } else {
199                         ret = 0;
200                 }
201         }
202
203         return ret;
204 }
205
206 int buxton_unregister_notification(BuxtonClient client,
207                                    BuxtonKey key,
208                                    BuxtonCallback callback,
209                                    void *data,
210                                    bool sync)
211 {
212         bool r;
213         int ret = 0;
214         _BuxtonKey *k = (_BuxtonKey *)key;
215
216         if (!k || !k->group.value || !k->name.value ||
217             k->type <= BUXTON_TYPE_MIN || k->type >= BUXTON_TYPE_MAX) {
218                 return EINVAL;
219         }
220
221         r = buxton_wire_unregister_notification((_BuxtonClient *)client, k,
222                                                 callback, data);
223         if (!r) {
224                 return -1;
225         }
226
227         if (sync) {
228                 ret = buxton_wire_get_response(client);
229                 if (ret <= 0) {
230                         ret = -1;
231                 } else {
232                         ret = 0;
233                 }
234         }
235
236         return ret;
237 }
238
239 int buxton_set_value(BuxtonClient client,
240                      BuxtonKey key,
241                      void *value,
242                      BuxtonCallback callback,
243                      void *data,
244                      bool sync)
245 {
246         bool r;
247         int ret = 0;
248         _BuxtonKey *k = (_BuxtonKey *)key;
249
250         if (!k || !k->group.value || !k->name.value || !k->layer.value ||
251             k->type <= BUXTON_TYPE_MIN || k->type >= BUXTON_TYPE_MAX || !value) {
252                 return EINVAL;
253         }
254
255         r = buxton_wire_set_value((_BuxtonClient *)client, k, value, callback,
256                                   data);
257         if (!r) {
258                 return -1;
259         }
260
261         if (sync) {
262                 ret = buxton_wire_get_response(client);
263                 if (ret <= 0) {
264                         ret = -1;
265                 } else {
266                         ret = 0;
267                 }
268         }
269
270         return ret;
271 }
272
273 int buxton_set_label(BuxtonClient client,
274                      BuxtonKey key,
275                      char *value,
276                      BuxtonCallback callback,
277                      void *data,
278                      bool sync)
279 {
280         bool r;
281         int ret = 0;
282         BuxtonString v;
283         _BuxtonKey *k = (_BuxtonKey *)key;
284
285         if (!k || !k->group.value || !k->layer.value || !value) {
286                 return EINVAL;
287         }
288
289         k->type = STRING;
290         v = buxton_string_pack(value);
291
292         r = buxton_wire_set_label((_BuxtonClient *)client, k, &v, callback,
293                                   data);
294         if (!r) {
295                 return -1;
296         }
297
298         if (sync) {
299                 ret = buxton_wire_get_response(client);
300                 if (ret <= 0) {
301                         ret = -1;
302                 } else {
303                         ret = 0;
304                 }
305         }
306
307         return ret;
308 }
309
310 int buxton_create_group(BuxtonClient client,
311                         BuxtonKey key,
312                         BuxtonCallback callback,
313                         void *data,
314                         bool sync)
315 {
316         bool r;
317         int ret = 0;
318         _BuxtonKey *k = (_BuxtonKey *)key;
319
320         /* We require the key name to be NULL, since it is not used for groups */
321         if (!k || !k->group.value || k->name.value || !k->layer.value) {
322                 return EINVAL;
323         }
324
325         k->type = STRING;
326         r = buxton_wire_create_group((_BuxtonClient *)client, k, callback, data);
327         if (!r) {
328                 return -1;
329         }
330
331         if (sync) {
332                 ret = buxton_wire_get_response(client);
333                 if (ret <= 0) {
334                         ret = -1;
335                 } else {
336                         ret = 0;
337                 }
338         }
339
340         return ret;
341 }
342
343 int buxton_remove_group(BuxtonClient client,
344                         BuxtonKey key,
345                         BuxtonCallback callback,
346                         void *data,
347                         bool sync)
348 {
349         bool r;
350         int ret = 0;
351         _BuxtonKey *k = (_BuxtonKey *)key;
352
353         /* We require the key name to be NULL, since it is not used for groups */
354         if (!k || !k->group.value || k->name.value || !k->layer.value) {
355                 return EINVAL;
356         }
357
358         k->type = STRING;
359         r = buxton_wire_remove_group((_BuxtonClient *)client, k, callback, data);
360         if (!r) {
361                 return -1;
362         }
363
364         if (sync) {
365                 ret = buxton_wire_get_response(client);
366                 if (ret <= 0) {
367                         ret = -1;
368                 } else {
369                         ret = 0;
370                 }
371         }
372
373         return ret;
374 }
375
376 int buxton_client_list_keys(BuxtonClient client,
377                             char *layer_name,
378                             BuxtonCallback callback,
379                             void *data,
380                             bool sync)
381 {
382         bool r;
383         int ret = 0;
384         BuxtonString l;
385
386         if (!layer_name) {
387                 return EINVAL;
388         }
389
390         l = buxton_string_pack(layer_name);
391
392         r = buxton_wire_list_keys((_BuxtonClient *)client, &l, callback, data);
393         if (!r) {
394                 return -1;
395         }
396
397         if (sync) {
398                 ret = buxton_wire_get_response(client);
399                 if (ret <= 0) {
400                         ret = -1;
401                 } else {
402                         ret = 0;
403                 }
404         }
405
406         return ret;
407 }
408
409 int buxton_unset_value(BuxtonClient client,
410                        BuxtonKey key,
411                        BuxtonCallback callback,
412                        void *data,
413                        bool sync)
414 {
415         bool r;
416         int ret = 0;
417         _BuxtonKey *k = (_BuxtonKey *)key;
418
419         if (!k || !k->group.value || !k->name.value || !k->layer.value ||
420             k->type <= BUXTON_TYPE_MIN || k->type >= BUXTON_TYPE_MAX) {
421                 return EINVAL;
422         }
423
424         r = buxton_wire_unset_value((_BuxtonClient *)client, k, callback, data);
425         if (!r) {
426                 return -1;
427         }
428
429         if (sync) {
430                 ret = buxton_wire_get_response(client);
431                 if (ret <= 0) {
432                         ret = -1;
433                 } else {
434                         ret = 0;
435                 }
436         }
437
438         return ret;
439 }
440
441 BuxtonKey buxton_key_create(char *group, char *name, char *layer,
442                           BuxtonDataType type)
443 {
444         _BuxtonKey *key = NULL;
445         char *g = NULL;
446         char *n = NULL;
447         char *l = NULL;
448
449         if (!group) {
450                 goto fail;
451         }
452
453         if (type <= BUXTON_TYPE_MIN || type >= BUXTON_TYPE_MAX) {
454                 goto fail;
455         }
456
457         if (!key_hash) {
458                 /* Create on hashmap on first call to key_create */
459                 key_hash = hashmap_new(trivial_hash_func, trivial_compare_func);
460                 if (!key_hash) {
461                         return NULL;
462                 }
463         }
464
465         g = strdup(group);
466         if (!g) {
467                 goto fail;
468         }
469
470         if (name) {
471                 n = strdup(name);
472                 if (!n) {
473                         goto fail;
474                 }
475         }
476
477         if (layer) {
478                 l = strdup(layer);
479                 if (!l) {
480                         goto fail;
481                 }
482         }
483
484         key = malloc0(sizeof(_BuxtonKey));
485         if (!key) {
486                 goto fail;
487         }
488
489         key->group.value = g;
490         key->group.length = (uint32_t)strlen(g) + 1;
491         if (name) {
492                 key->name.value = n;
493                 key->name.length = (uint32_t)strlen(n) + 1;
494         } else {
495                 key->name.value = NULL;
496                 key->name.length = 0;
497         }
498         if (layer) {
499                 key->layer.value = l;
500                 key->layer.length = (uint32_t)strlen(l) + 1;
501         } else {
502                 key->layer.value = NULL;
503                 key->layer.length = 0;
504         }
505         key->type = type;
506
507         /* Add new keys to internal hash for cleanup on close */
508         hashmap_put(key_hash, key, key);
509
510         return (BuxtonKey)key;
511
512 fail:
513         free(g);
514         free(n);
515         free(l);
516         return NULL;
517 }
518
519 char *buxton_key_get_group(BuxtonKey key)
520 {
521         _BuxtonKey *k = (_BuxtonKey *)key;
522
523         if (!key) {
524                 return NULL;
525         }
526
527         return get_group(k);
528 }
529
530 char *buxton_key_get_name(BuxtonKey key)
531 {
532         _BuxtonKey *k = (_BuxtonKey *)key;
533
534         if (!key) {
535                 return NULL;
536         }
537
538         return get_name(k);
539 }
540
541 char *buxton_key_get_layer(BuxtonKey key)
542 {
543         _BuxtonKey *k = (_BuxtonKey *)key;
544
545         if (!key) {
546                 return NULL;
547         }
548
549         return get_layer(k);
550 }
551
552 BuxtonDataType buxton_key_get_type(BuxtonKey key)
553 {
554         _BuxtonKey *k = (_BuxtonKey *)key;
555
556         if (!key) {
557                 return -1;
558         }
559
560         return k->type;
561 }
562
563 void buxton_key_free(BuxtonKey key)
564 {
565         _BuxtonKey *k = (_BuxtonKey *)key;
566
567         if (!k) {
568                 return;
569         }
570
571         hashmap_remove_value(key_hash, key, key);
572
573         free(k->group.value);
574         free(k->name.value);
575         free(k->layer.value);
576         free(k);
577 }
578
579 ssize_t buxton_client_handle_response(BuxtonClient client)
580 {
581         return buxton_wire_handle_response((_BuxtonClient *)client);
582 }
583
584 BuxtonControlMessage buxton_response_type(BuxtonResponse response)
585 {
586         _BuxtonResponse *r = (_BuxtonResponse *)response;
587
588         if (!response) {
589                 return -1;
590         }
591
592         return r->type;
593 }
594
595 int32_t buxton_response_status(BuxtonResponse response)
596 {
597         BuxtonData *d;
598         _BuxtonResponse *r = (_BuxtonResponse *)response;
599
600         if (!response) {
601                 return -1;
602         }
603
604         if (buxton_response_type(response) == BUXTON_CONTROL_CHANGED) {
605                 return 0;
606         }
607
608         d = buxton_array_get(r->data, 0);
609
610         if (d) {
611                 return d->store.d_int32;
612         }
613
614         return -1;
615 }
616
617 BuxtonKey buxton_response_key(BuxtonResponse response)
618 {
619         _BuxtonKey *key = NULL;
620         _BuxtonResponse *r = (_BuxtonResponse *)response;
621
622         if (!response) {
623                 return NULL;
624         }
625
626         if (buxton_response_type(response) == BUXTON_CONTROL_LIST) {
627                 return NULL;
628         }
629
630         key = malloc0(sizeof(_BuxtonKey));
631         if (!key) {
632                 return NULL;
633         }
634
635         if (!buxton_key_copy(r->key, key)) {
636                 free(key);
637                 return NULL;
638         }
639
640         return (BuxtonKey)key;
641 }
642
643 void *buxton_response_value(BuxtonResponse response)
644 {
645         void *p = NULL;
646         BuxtonData *d = NULL;
647         _BuxtonResponse *r = (_BuxtonResponse *)response;
648         BuxtonControlMessage type;
649
650         if (!response) {
651                 return NULL;
652         }
653
654         type = buxton_response_type(response);
655         if (type == BUXTON_CONTROL_GET) {
656                 d = buxton_array_get(r->data, 1);
657         } else if (type == BUXTON_CONTROL_CHANGED) {
658                 if (r->data->len) {
659                         d = buxton_array_get(r->data, 0);
660                 }
661         } else {
662                 goto out;
663         }
664
665         if (!d) {
666                 goto out;
667         }
668
669         switch (d->type) {
670         case STRING:
671                 return strdup(d->store.d_string.value);
672         case INT32:
673                 p = malloc0(sizeof(int32_t));
674                 if (!p) {
675                         goto out;
676                 }
677                 *(int32_t *)p = (int32_t)d->store.d_int32;
678                 break;
679         case UINT32:
680                 p = malloc0(sizeof(uint32_t));
681                 if (!p) {
682                         goto out;
683                 }
684                 *(uint32_t *)p = (uint32_t)d->store.d_uint32;
685                 break;
686         case INT64:
687                 p = malloc0(sizeof(int64_t));
688                 if (!p) {
689                         goto out;
690                 }
691                 *(int64_t *)p = (int64_t)d->store.d_int64;
692                 break;
693         case UINT64:
694                 p = malloc0(sizeof(uint64_t));
695                 if (!p) {
696                         goto out;
697                 }
698                 *(uint64_t *)p = (uint64_t)d->store.d_uint64;
699                 break;
700         case FLOAT:
701                 p = malloc0(sizeof(float));
702                 if (!p) {
703                         goto out;
704                 }
705                 *(float *)p = (float)d->store.d_float;
706                 break;
707         case DOUBLE:
708                 p = malloc0(sizeof(double));
709                 if (!p) {
710                         goto out;
711                 }
712                 *(double *)p = (double)d->store.d_double;
713                 break;
714         case BOOLEAN:
715                 p = malloc0(sizeof(bool));
716                 if (!p) {
717                         goto out;
718                 }
719                 *(bool *)p = (bool)d->store.d_boolean;
720                 break;
721         default:
722                 break;
723         }
724
725 out:
726         return p;
727 }
728
729 /*
730  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
731  *
732  * Local variables:
733  * c-basic-offset: 8
734  * tab-width: 8
735  * indent-tabs-mode: t
736  * End:
737  *
738  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
739  * :indentSize=8:tabSize=8:noTabs=false:
740  */