Initialize the project.
[apps/livebox/data-provider-master.git] / src / client_life.c
1 /*
2  * Copyright 2012  Samsung Electronics Co., Ltd
3  *
4  * Licensed under the Flora License, Version 1.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.tizenopensource.org/license
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <stdio.h>
18 #include <errno.h>
19
20 #include <Eina.h>
21 #include <Ecore.h>
22
23 #include <dlog.h>
24 #include <packet.h>
25
26 #include "client_life.h"
27 #include "instance.h"
28 #include "client_rpc.h"
29 #include "debug.h"
30 #include "util.h"
31 #include "slave_life.h"
32 #include "xmonitor.h"
33 #include "conf.h"
34
35 int errno;
36
37 static struct {
38         Eina_List *client_list;
39         int nr_of_paused_clients;
40
41         Eina_List *create_event_list;
42         Eina_List *destroy_event_list;
43 } s_info = {
44         .client_list = NULL,
45         .nr_of_paused_clients = 0,
46         .create_event_list = NULL,
47         .destroy_event_list = NULL,
48 };
49
50 struct subscribe_item {
51         char *cluster;
52         char *category;
53 };
54
55 struct global_event_handler {
56         void *cbdata;
57         int (*cb)(struct client_node *client, void *data);
58 };
59
60 struct data_item {
61         char *tag;
62         void *data;
63 };
64
65 struct event_item {
66         void *data;
67         int (*cb)(struct client_node *, void *);
68 };
69
70 struct client_node {
71         pid_t pid;
72         int refcnt;
73
74         int paused;
75
76         Eina_List *event_deactivate_list;
77         Eina_List *event_destroy_list;
78         Eina_List *data_list;
79         Eina_List *subscribe_list;
80
81         int faulted;
82 };
83
84 static inline void invoke_global_destroy_cb(struct client_node *client)
85 {
86         Eina_List *l;
87         Eina_List *n;
88         struct global_event_handler *item;
89         int ret;
90
91         EINA_LIST_FOREACH_SAFE(s_info.destroy_event_list, l, n, item) {
92                 if (!item->cb) {
93                         DbgPrint("Callback function is not valid\n");
94                         continue;
95                 }
96
97                 ret = item->cb(client, item->cbdata);
98
99                 if (ret < 0) {
100                         if (eina_list_data_find(s_info.destroy_event_list, item)) {
101                                 s_info.destroy_event_list = eina_list_remove(s_info.destroy_event_list, item);
102                                 DbgFree(item);
103                         }
104                 }
105         }
106 }
107
108 static inline void invoke_global_create_cb(struct client_node *client)
109 {
110         Eina_List *l;
111         Eina_List *n;
112         struct global_event_handler *item;
113
114         EINA_LIST_FOREACH_SAFE(s_info.create_event_list, l, n, item) {
115                 if (item->cb(client, item->cbdata) < 0) {
116                         if (eina_list_data_find(s_info.create_event_list, item)) {
117                                 s_info.create_event_list = eina_list_remove(s_info.create_event_list, item);
118                                 DbgFree(item);
119                         }
120                 }
121         }
122 }
123
124 static inline void destroy_client_data(struct client_node *client)
125 {
126         struct event_item *event;
127         struct data_item *data;
128         struct subscribe_item *item;
129         Eina_List *l;
130         Eina_List *n;
131
132         DbgPrint("Client %p is destroyed\n", client);
133
134         invoke_global_destroy_cb(client);
135         client_rpc_fini(client); /*!< Finalize the RPC after invoke destroy callbacks */
136
137         EINA_LIST_FOREACH_SAFE(client->event_destroy_list, l, n, event) {
138                 if (!event->cb) {
139                         DbgPrint("Callback function is not valid\n");
140                         continue;
141                 }
142
143                 event->cb(client, event->data);
144
145                 if (eina_list_data_find(client->event_destroy_list, event)) {
146                         client->event_destroy_list = eina_list_remove(client->event_destroy_list, event);
147                         DbgFree(event);
148                 }
149         }
150
151         EINA_LIST_FREE(client->data_list, data) {
152                 DbgPrint("Tag is not cleared (%s)\n", data->tag);
153                 DbgFree(data->tag);
154                 DbgFree(data);
155         }
156
157         EINA_LIST_FREE(client->event_deactivate_list, event) {
158                 DbgFree(event);
159         }
160
161         EINA_LIST_FREE(client->subscribe_list, item) {
162                 DbgFree(item->cluster);
163                 DbgFree(item->category);
164                 DbgFree(item);
165         }
166
167         if (client->paused)
168                 s_info.nr_of_paused_clients--;
169
170         s_info.client_list = eina_list_remove(s_info.client_list, client);
171         DbgFree(client);
172
173         /*!
174          * \note
175          * If there is any changes of clients,
176          * We should check the pause/resume states again.
177          */
178         xmonitor_handle_state_changes();
179 }
180
181 static inline struct client_node *create_client_data(pid_t pid)
182 {
183         struct client_node *client;
184
185         client = calloc(1, sizeof(*client));
186         if (!client) {
187                 ErrPrint("Heap: %s\n", strerror(errno));
188                 return NULL;
189         }
190
191         client->pid = pid;
192         client->refcnt = 1;
193
194         s_info.client_list = eina_list_append(s_info.client_list, client);
195         return client;
196 }
197
198 static Eina_Bool created_cb(void *data)
199 {
200         invoke_global_create_cb(data);
201         return ECORE_CALLBACK_CANCEL;
202 }
203
204 HAPI struct client_node *client_create(pid_t pid, int handle)
205 {
206         struct client_node *client;
207         int ret;
208
209         client = client_find_by_pid(pid);
210         if (client) {
211                 ErrPrint("Client %d is already exists\n", pid);
212                 return client;
213         }
214
215         client = create_client_data(pid);
216         if (!client) {
217                 ErrPrint("Failed to create a new client (%d)\n", pid);
218                 return NULL;
219         }
220
221         ret = client_rpc_init(client, handle);
222         if (ret < 0) {
223                 client = client_unref(client);
224                 ErrPrint("Failed to initialize the RPC for %d, Destroy client data %p(has to be 0x0)\n", pid, client);
225         } else {
226                 if (ecore_timer_add(DELAY_TIME, created_cb, client) == NULL) {
227                         ErrPrint("Failed to add a timer for client created event\n");
228                         client = client_unref(client);
229                         return NULL;
230                 }
231
232                 xmonitor_update_state(pid);
233         }
234
235         return client;
236 }
237
238 HAPI int client_destroy(struct client_node *client)
239 {
240         client_unref(client);
241         return 0;
242 }
243
244 HAPI struct client_node *client_ref(struct client_node *client)
245 {
246         if (!client)
247                 return NULL;
248
249         client->refcnt++;
250         return client;
251 }
252
253 HAPI struct client_node *client_unref(struct client_node *client)
254 {
255         if (!client)
256                 return NULL;
257
258         if (client->refcnt == 0) {
259                 ErrPrint("Client refcnt is not managed correctly\n");
260                 return NULL;
261         }
262
263         client->refcnt--;
264         if (client->refcnt == 0) {
265                 destroy_client_data(client);
266                 client = NULL;
267         }
268
269         return client;
270 }
271
272 HAPI const int const client_refcnt(const struct client_node *client)
273 {
274         return client->refcnt;
275 }
276
277 HAPI const pid_t const client_pid(const struct client_node *client)
278 {
279         return client ? client->pid : (pid_t)-1;
280 }
281
282 HAPI struct client_node *client_find_by_pid(pid_t pid)
283 {
284         Eina_List *l;
285         struct client_node *client;
286
287         EINA_LIST_FOREACH(s_info.client_list, l, client) {
288                 if (client->pid == pid)
289                         return client;
290         }
291
292         return NULL;
293 }
294
295 HAPI struct client_node *client_find_by_rpc_handle(int handle)
296 {
297         Eina_List *l;
298         struct client_node *client;
299
300         if (handle <= 0) {
301                 ErrPrint("Invalid handle %d\n", handle);
302                 return NULL;
303         }
304
305         EINA_LIST_FOREACH(s_info.client_list, l, client) {
306                 if (client_rpc_handle(client) == handle)
307                         return client;
308         }
309
310         return NULL;
311 }
312
313 HAPI const int const client_count_paused(void)
314 {
315         return s_info.nr_of_paused_clients;
316 }
317
318 HAPI int client_is_all_paused(void)
319 {
320         DbgPrint("%d, %d\n", eina_list_count(s_info.client_list), s_info.nr_of_paused_clients);
321         return eina_list_count(s_info.client_list) == s_info.nr_of_paused_clients;
322 }
323
324 HAPI int client_count(void)
325 {
326         return eina_list_count(s_info.client_list);
327 }
328
329 static inline void invoke_deactivated_cb(struct client_node *client)
330 {
331         struct event_item *item;
332         Eina_List *l;
333         Eina_List *n;
334         int ret;
335
336         client_ref(client); /*!< Prevent deleting from callback */
337         EINA_LIST_FOREACH_SAFE(client->event_deactivate_list, l, n, item) {
338                 ret = item->cb(client, item->data);
339                 if (ret < 0) {
340                         if (eina_list_data_find(client->event_deactivate_list, item)) {
341                                 client->event_deactivate_list = eina_list_remove(client->event_deactivate_list, item);
342                                 DbgFree(item);
343                         }
344                 }
345         }
346         client_unref(client);
347 }
348
349 HAPI int client_deactivated_by_fault(struct client_node *client)
350 {
351         if (!client || client->faulted)
352                 return 0;
353
354         DbgPrint("Client[%p] is faulted(%d), pid(%d)\n", client, client->refcnt, client->pid);
355         client->faulted = 1;
356
357         DbgPrint("Reset PID (%d)\n", client->pid);
358         client->pid = (pid_t)-1;
359
360         invoke_deactivated_cb(client);
361         client_destroy(client);
362         /*!
363          * \todo
364          * Who invokes this function has to care the reference counter of a client
365          * do I need to invoke the deactivated callback from here?
366          * client->pid = (pid_t)-1;
367          * slave_unref(client)
368          */
369         return 0;
370 }
371
372 HAPI const int const client_is_faulted(const struct client_node *client)
373 {
374         /*!
375          * \note
376          * If the "client" is NIL, I assume that it is fault so returns TRUE(1)
377          */
378         return client ? client->faulted : 1;
379 }
380
381 HAPI void client_reset_fault(struct client_node *client)
382 {
383         if (client)
384                 client->faulted = 0;
385 }
386
387 HAPI int client_event_callback_add(struct client_node *client, enum client_event event, int (*cb)(struct client_node *, void *), void *data)
388 {
389         struct event_item *item;
390
391         if (!cb) {
392                 ErrPrint("Invalid callback (cb == NULL)\n");
393                 return -EINVAL;
394         }
395
396         item = calloc(1, sizeof(*item));
397         if (!item) {
398                 ErrPrint("Heap: %s\n", strerror(errno));
399                 return -ENOMEM;
400         }
401
402         item->cb = cb;
403         item->data = data;
404
405         /*!
406          * \note
407          * Use the eina_list_prepend API.
408          * To keep the sequence of a callback invocation.
409          *
410          * Here is an example sequence.
411          *
412          * client_event_callback_add(CALLBACK_01);
413          * client_event_callback_add(CALLBACK_02);
414          * client_event_callback_add(CALLBACK_03);
415          *
416          * Then the invoke_event_callback function will call the CALLBACKS as below sequence
417          *
418          * invoke_CALLBACK_03
419          * invoke_CALLBACK_02
420          * invoke_CALLBACK_01
421          */
422
423         switch (event) {
424         case CLIENT_EVENT_DEACTIVATE:
425                 client->event_deactivate_list = eina_list_prepend(client->event_deactivate_list, item);
426                 break;
427         case CLIENT_EVENT_DESTROY:
428                 client->event_destroy_list = eina_list_prepend(client->event_destroy_list, item);
429                 break;
430         default:
431                 DbgFree(item);
432                 return -EINVAL;
433         }
434
435         return 0;
436 }
437
438 HAPI int client_event_callback_del(struct client_node *client, enum client_event event, int (*cb)(struct client_node *, void *), void *data)
439 {
440         struct event_item *item;
441         Eina_List *l;
442         Eina_List *n;
443
444         if (!cb) {
445                 ErrPrint("Invalid callback (cb == NULL)\n");
446                 return -EINVAL;
447         }
448
449         switch (event) {
450         case CLIENT_EVENT_DEACTIVATE:
451                 EINA_LIST_FOREACH_SAFE(client->event_deactivate_list, l, n, item) {
452                         if (item->cb == cb && item->data == data) {
453                                 client->event_deactivate_list = eina_list_remove(client->event_deactivate_list, item);
454                                 DbgFree(item);
455                                 return 0;
456                         }
457                 }
458                 break;
459
460         case CLIENT_EVENT_DESTROY:
461                 EINA_LIST_FOREACH_SAFE(client->event_destroy_list, l, n, item) {
462                         if (item->cb == cb && item->data == data) {
463                                 client->event_destroy_list = eina_list_remove(client->event_destroy_list, item);
464                                 DbgFree(item);
465                                 return 0;
466                         }
467                 }
468                 break;
469
470         default:
471                 ErrPrint("Invalid event\n");
472                 break;
473         }
474
475         return -ENOENT;
476 }
477
478 HAPI int client_set_data(struct client_node *client, const char *tag, void *data)
479 {
480         struct data_item *item;
481
482         item = calloc(1, sizeof(*item));
483         if (!item) {
484                 ErrPrint("Heap: %s\n", strerror(errno));
485                 return -ENOMEM;
486         }
487
488         item->tag = strdup(tag);
489         if (!item->tag) {
490                 ErrPrint("Heap: %s\n", strerror(errno));
491                 DbgFree(item);
492                 return -ENOMEM;
493         }
494
495         item->data = data;
496
497         client->data_list = eina_list_append(client->data_list, item);
498         return 0;
499 }
500
501 HAPI void *client_data(struct client_node *client, const char *tag)
502 {
503         Eina_List *l;
504         struct data_item *item;
505
506         EINA_LIST_FOREACH(client->data_list, l, item) {
507                 if (!strcmp(item->tag, tag))
508                         return item->data;
509         }
510
511         return NULL;
512 }
513
514 HAPI void *client_del_data(struct client_node *client, const char *tag)
515 {
516         Eina_List *l;
517         Eina_List *n;
518         struct data_item *item;
519
520         EINA_LIST_FOREACH_SAFE(client->data_list, l, n, item) {
521                 if (!strcmp(item->tag, tag)) {
522                         void *data;
523                         client->data_list = eina_list_remove(client->data_list, item);
524                         data = item->data;
525                         DbgFree(item->tag);
526                         DbgFree(item);
527                         return data;
528                 }
529         }
530
531         return NULL;
532 }
533
534 HAPI void client_paused(struct client_node *client)
535 {
536         if (client->paused)
537                 return;
538
539         client->paused = 1;
540         s_info.nr_of_paused_clients++;
541 }
542
543 HAPI void client_resumed(struct client_node *client)
544 {
545         if (client->paused == 0)
546                 return;
547
548         client->paused = 0;
549         s_info.nr_of_paused_clients--;
550 }
551
552 HAPI int client_init(void)
553 {
554         return 0;
555 }
556
557 HAPI int client_fini(void)
558 {
559         struct global_event_handler *handler;
560         struct client_node *client;
561         Eina_List *l;
562         Eina_List *n;
563
564         EINA_LIST_FOREACH_SAFE(s_info.client_list, l, n, client) {
565                 client_destroy(client);
566         }
567
568         EINA_LIST_FREE(s_info.create_event_list, handler) {
569                 DbgFree(handler);
570         }
571
572         EINA_LIST_FREE(s_info.destroy_event_list, handler) {
573                 DbgFree(handler);
574         }
575
576         return 0;
577 }
578
579 HAPI const int const client_is_activated(const struct client_node *client)
580 {
581         return client ? (client->pid != (pid_t)-1) : 1;
582 }
583
584 HAPI int client_global_event_handler_add(enum client_global_event event_type, int (*cb)(struct client_node *client, void *data), void *data)
585 {
586         struct global_event_handler *handler;
587
588         handler = malloc(sizeof(*handler));
589         if (!handler) {
590                 ErrPrint("Heap: %s\n", strerror(errno));
591                 return -ENOMEM;
592         }
593
594         handler->cbdata = data;
595         handler->cb = cb;
596
597         switch (event_type) {
598         case CLIENT_GLOBAL_EVENT_CREATE:
599                 s_info.create_event_list = eina_list_prepend(s_info.create_event_list, handler);
600                 break;
601         case CLIENT_GLOBAL_EVENT_DESTROY:
602                 s_info.destroy_event_list = eina_list_prepend(s_info.destroy_event_list, handler);
603                 break;
604         default:
605                 DbgFree(handler);
606                 return -EINVAL;
607         }
608
609         return 0;
610 }
611
612 HAPI int client_global_event_handler_del(enum client_global_event event_type, int (*cb)(struct client_node *, void *), void *data)
613 {
614         Eina_List *l;
615         Eina_List *n;
616         struct global_event_handler *handler;
617
618         switch (event_type) {
619         case CLIENT_GLOBAL_EVENT_CREATE:
620                 EINA_LIST_FOREACH_SAFE(s_info.create_event_list, l, n, handler) {
621                         if (handler->cb == cb && handler->cbdata == data) {
622                                 s_info.create_event_list = eina_list_remove(s_info.create_event_list, handler);
623                                 DbgFree(handler);
624                                 return 0;
625                         }
626                 }
627                 break;
628         case CLIENT_GLOBAL_EVENT_DESTROY:
629                 EINA_LIST_FOREACH_SAFE(s_info.destroy_event_list, l, n, handler) {
630                         if (handler->cb == cb && handler->cbdata == data) {
631                                 s_info.destroy_event_list = eina_list_remove(s_info.destroy_event_list, handler);
632                                 DbgFree(handler);
633                                 return 0;
634                         }
635                 }
636                 break;
637         default:
638                 break;
639         }
640
641         return -ENOENT;
642 }
643
644 HAPI int client_subscribe(struct client_node *client, const char *cluster, const char *category)
645 {
646         struct subscribe_item *item;
647
648         item = malloc(sizeof(*item));
649         if (!item) {
650                 ErrPrint("Heap: %s\n", strerror(errno));
651                 return -ENOMEM;
652         }
653
654         item->cluster = strdup(cluster);
655         if (!item->cluster) {
656                 ErrPrint("Heap: %s\n", strerror(errno));
657                 DbgFree(item);
658                 return -ENOMEM;
659         }
660
661         item->category = strdup(category);
662         if (!item->category) {
663                 ErrPrint("Heap: %s\n", strerror(errno));
664                 DbgFree(item->cluster);
665                 DbgFree(item);
666                 return -ENOMEM;
667         }
668
669         client->subscribe_list = eina_list_append(client->subscribe_list, item);
670         return 0;
671 }
672
673 HAPI int client_unsubscribe(struct client_node *client, const char *cluster, const char *category)
674 {
675         struct subscribe_item *item;
676         Eina_List *l;
677         Eina_List *n;
678
679         EINA_LIST_FOREACH_SAFE(client->subscribe_list, l, n, item) {
680                 if (!strcasecmp(cluster, item->cluster) && !strcasecmp(category, item->category)) {
681                         client->subscribe_list = eina_list_remove(client->subscribe_list, item);
682                         DbgFree(item->cluster);
683                         DbgFree(item->category);
684                         DbgFree(item);
685                         return 0;
686                 }
687         }
688
689         return -ENOENT;
690 }
691
692 HAPI int client_is_subscribed(struct client_node *client, const char *cluster, const char *category)
693 {
694         struct subscribe_item *item;
695         Eina_List *l;
696
697         EINA_LIST_FOREACH(client->subscribe_list, l, item) {
698                 if (!strcmp(item->cluster, "*"))
699                         return 1;
700
701                 if (strcasecmp(item->cluster, cluster))
702                         continue;
703
704                 if (!strcmp(item->category, "*"))
705                         return 1;
706
707                 if (!strcasecmp(item->category, category))
708                         return 1;
709         }
710
711         return 0;
712 }
713
714 HAPI int client_browse_list(const char *cluster, const char *category, int (*cb)(struct client_node *client, void *data), void *data)
715 {
716         Eina_List *l;
717         struct client_node *client;
718         int cnt;
719
720         cnt = 0;
721         EINA_LIST_FOREACH(s_info.client_list, l, client) {
722                 if (!client_is_subscribed(client, cluster, category))
723                         continue;
724
725                 if (cb) {
726                         if (cb(client, data) < 0)
727                                 return -ECANCELED;
728                 }
729                 cnt++;
730         }
731
732         return cnt;
733 }
734
735 HAPI int client_nr_of_subscriber(const char *cluster, const char *category)
736 {
737         Eina_List *l;
738         struct client_node *client;
739         int cnt;
740
741         cnt = 0;
742         EINA_LIST_FOREACH(s_info.client_list, l, client) {
743                 cnt += !!client_is_subscribed(client, cluster, category);
744         }
745
746         return cnt;
747 }
748
749 HAPI int client_broadcast(struct inst_info *inst, struct packet *packet)
750 {
751         Eina_List *l;
752         Eina_List *list;
753         struct client_node *client;
754
755         list = inst ? instance_client_list(inst) : s_info.client_list;
756         EINA_LIST_FOREACH(list, l, client) {
757                 if (client_pid(client) < 0) {
758                         ErrPrint("Client[%p] has PID[%d]\n", client, client_pid(client));
759                         continue;
760                 }
761
762                 (void)client_rpc_async_request(client, packet_ref(packet));
763         }
764
765         packet_unref(packet);
766         return 0;
767 }
768
769 /* End of a file */