6006371279232b8b60ef160312b3e00529715ee1
[platform/core/appfw/data-provider-master.git] / src / client_life.c
1 /*
2  * Copyright 2013  Samsung Electronics Co., Ltd
3  *
4  * Licensed under the Flora License, Version 1.1 (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://floralicense.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 #include <unistd.h>
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <fcntl.h>
23 #include <sys/smack.h>
24
25 #include <Eina.h>
26 #include <Ecore.h>
27
28 #include <dlog.h>
29 #include <packet.h>
30 #include <dynamicbox_errno.h>
31
32 #include "client_life.h"
33 #include "instance.h"
34 #include "client_rpc.h"
35 #include "debug.h"
36 #include "util.h"
37 #include "slave_life.h"
38 #include "xmonitor.h"
39 #include "conf.h"
40
41 int errno;
42
43 static struct {
44         Eina_List *client_list;
45         int nr_of_paused_clients;
46
47         enum global_event_process {
48                 GLOBAL_EVENT_PROCESS_IDLE = 0x00,
49                 GLOBAL_EVENT_PROCESS_CREATE = 0x01,
50                 GLOBAL_EVENT_PROCESS_DESTROY = 0x02
51         } in_event_process;
52
53         Eina_List *create_event_list;
54         Eina_List *destroy_event_list;
55
56 } s_info = {
57         .client_list = NULL,
58         .nr_of_paused_clients = 0,
59         .in_event_process = GLOBAL_EVENT_PROCESS_IDLE,
60         .create_event_list = NULL,
61         .destroy_event_list = NULL,
62 };
63
64 struct subscribe_item {
65         char *cluster;
66         char *category;
67 };
68
69 struct global_event_item {
70         void *cbdata;
71         int (*cb)(struct client_node *client, void *data);
72         int deleted;
73 };
74
75 struct event_item {
76         void *data;
77         int (*cb)(struct client_node *, void *);
78         int deleted;
79 };
80
81 struct data_item {
82         char *tag;
83         void *data;
84 };
85
86 struct client_node {
87         pid_t pid;
88         int refcnt;
89
90         int paused;
91
92         enum client_event_process {
93                 CLIENT_EVENT_PROCESS_IDLE = 0x00,
94                 CLIENT_EVENT_PROCESS_DEACTIVATE = 0x01,
95                 CLIENT_EVENT_PROCESS_ACTIVATE = 0x02
96         } in_event_process;
97         Eina_List *event_deactivate_list;
98         Eina_List *event_activate_list;
99
100         Eina_List *data_list;
101         Eina_List *subscribe_list;
102
103         int faulted;
104         char *direct_addr;
105 };
106
107 static inline void invoke_global_destroyed_cb(struct client_node *client)
108 {
109         Eina_List *l;
110         Eina_List *n;
111         struct global_event_item *item;
112
113         s_info.in_event_process |= GLOBAL_EVENT_PROCESS_DESTROY;
114         EINA_LIST_FOREACH_SAFE(s_info.destroy_event_list, l, n, item) {
115                 /*!
116                  * The first,
117                  * item->deleted will be checked, so if it is deleted, remove item from the list
118                  * The second, if the first routine takes false path,
119                  * item->cb will be called, if it returns negative value, remove item from the list
120                  * The third, if the second routine takes false path,
121                  * Check the item->deleted again, so if it is turnned on, remove item from the list
122                  */
123                 if (item->deleted || item->cb(client, item->cbdata) < 0 || item->deleted) {
124                         s_info.destroy_event_list = eina_list_remove(s_info.destroy_event_list, item);
125                         DbgFree(item);
126                 }
127         }
128         s_info.in_event_process &= ~GLOBAL_EVENT_PROCESS_DESTROY;
129 }
130
131 static inline void invoke_global_created_cb(struct client_node *client)
132 {
133         Eina_List *l;
134         Eina_List *n;
135         struct global_event_item *item;
136
137         s_info.in_event_process |= GLOBAL_EVENT_PROCESS_CREATE;
138         EINA_LIST_FOREACH_SAFE(s_info.create_event_list, l, n, item) {
139                 /*!
140                  * The first,
141                  * item->deleted will be checked, so if it is deleted, remove item from the list
142                  * The second, if the first routine takes false path,
143                  * item->cb will be called, if it returns negative value, remove item from the list
144                  * The third, if the second routine takes false path,
145                  * Check the item->deleted again, so if it is turnned on, remove item from the list
146                  */
147
148                 if (item->deleted || item->cb(client, item->cbdata) < 0 || item->deleted) {
149                         s_info.create_event_list = eina_list_remove(s_info.create_event_list, item);
150                         DbgFree(item);
151                 }
152         }
153         s_info.in_event_process &= ~GLOBAL_EVENT_PROCESS_CREATE;
154 }
155
156 static inline void invoke_deactivated_cb(struct client_node *client)
157 {
158         struct event_item *item;
159         Eina_List *l;
160         Eina_List *n;
161
162         client->in_event_process |= CLIENT_EVENT_PROCESS_DEACTIVATE;
163         EINA_LIST_FOREACH_SAFE(client->event_deactivate_list, l, n, item) {
164                 /*!
165                  * The first,
166                  * item->deleted will be checked, so if it is deleted, remove item from the list
167                  * The second, if the first routine takes false path,
168                  * item->cb will be called, if it returns negative value, remove item from the list
169                  * The third, if the second routine takes false path,
170                  * Check the item->deleted again, so if it is turnned on, remove item from the list
171                  */
172
173                 if (item->deleted || item->cb(client, item->data) < 0 || item->deleted) {
174                         client->event_deactivate_list = eina_list_remove(client->event_deactivate_list, item);
175                         DbgFree(item);
176                 }
177         }
178         client->in_event_process &= ~CLIENT_EVENT_PROCESS_DEACTIVATE;
179 }
180
181 static inline void invoke_activated_cb(struct client_node *client)
182 {
183         struct event_item *item;
184         Eina_List *l;
185         Eina_List *n;
186
187         client->in_event_process |= CLIENT_EVENT_PROCESS_ACTIVATE;
188         EINA_LIST_FOREACH_SAFE(client->event_activate_list, l, n, item) {
189                 /*!
190                  * The first,
191                  * item->deleted will be checked, so if it is deleted, remove item from the list
192                  * The second, if the first routine takes false path,
193                  * item->cb will be called, if it returns negative value, remove item from the list
194                  * The third, if the second routine takes false path,
195                  * Check the item->deleted again, so if it is turnned on, remove item from the list
196                  */
197
198                 if (item->deleted || item->cb(client, item->data) < 0 || item->deleted) {
199                         client->event_activate_list = eina_list_remove(client->event_activate_list, item);
200                         DbgFree(item);
201                 }
202         }
203         client->in_event_process &= ~CLIENT_EVENT_PROCESS_ACTIVATE;
204 }
205
206 static inline void destroy_client_data(struct client_node *client)
207 {
208         struct event_item *event;
209         struct data_item *data;
210         struct subscribe_item *item;
211         Ecore_Timer *timer;
212
213         timer = client_del_data(client, "create,timer");
214         if (timer) {
215                 ecore_timer_del(timer);
216         }
217
218         DbgPrint("Destroy client: %p\n", client);
219
220         invoke_global_destroyed_cb(client);
221         client_rpc_fini(client); /*!< Finalize the RPC after invoke destroy callbacks */
222
223         EINA_LIST_FREE(client->data_list, data) {
224                 DbgPrint("Tag is not cleared (%s)\n", data->tag);
225                 DbgFree(data->tag);
226                 DbgFree(data);
227         }
228
229         EINA_LIST_FREE(client->event_deactivate_list, event) {
230                 DbgFree(event);
231         }
232
233         EINA_LIST_FREE(client->subscribe_list, item) {
234                 DbgFree(item->cluster);
235                 DbgFree(item->category);
236                 DbgFree(item);
237         }
238
239         if (client->paused) {
240                 s_info.nr_of_paused_clients--;
241         }
242
243         if (client->direct_addr) {
244                 (void)unlink(client->direct_addr);
245                 DbgFree(client->direct_addr);
246         }
247
248         s_info.client_list = eina_list_remove(s_info.client_list, client);
249         DbgFree(client);
250
251         /*!
252          * \note
253          * If there is any changes of clients,
254          * We should check the pause/resume states again.
255          */
256         xmonitor_handle_state_changes();
257 }
258
259 static inline struct client_node *create_client_data(pid_t pid, const char *direct_addr)
260 {
261         struct client_node *client;
262
263         client = calloc(1, sizeof(*client));
264         if (!client) {
265                 ErrPrint("Heap: %s\n", strerror(errno));
266                 return NULL;
267         }
268
269         client->pid = pid;
270         client->refcnt = 1;
271
272         if (direct_addr && direct_addr[0]) {
273                 client->direct_addr = strdup(direct_addr);
274                 if (!client->direct_addr) {
275                         ErrPrint("Failed to allocate direct_addr (%s)\n", direct_addr);
276                 }
277         }
278
279         s_info.client_list = eina_list_append(s_info.client_list, client);
280
281         /*!
282          * \note
283          * Right after create a client ADT,
284          * We assume that the client is paused.
285          */
286         client_paused(client);
287         xmonitor_handle_state_changes();
288         return client;
289 }
290
291 static Eina_Bool created_cb(void *data)
292 {
293         (void)client_del_data(data, "create,timer");
294
295         invoke_global_created_cb(data);
296         invoke_activated_cb(data);
297         /*!
298          * \note
299          * Client PAUSE/RESUME event must has to be sent after created event.
300          */
301         xmonitor_update_state(client_pid(data));
302
303         (void)client_unref(data);
304         return ECORE_CALLBACK_CANCEL;
305 }
306
307 /*!
308  * \note
309  * Noramlly, client ADT is created when it send the "acquire" packet.
310  * It means we have the handle for communicating with the client already,
311  * So we just create its ADT in this function.
312  * And invoke the global created event & activated event callbacks
313  */
314 HAPI struct client_node *client_create(pid_t pid, int handle, const char *direct_addr)
315 {
316         struct client_node *client;
317         int ret;
318
319         client = client_find_by_rpc_handle(handle);
320         if (client) {
321                 ErrPrint("Client %d(%d) is already exists\n", pid, handle);
322                 return client;
323         }
324
325         client = create_client_data(pid, direct_addr);
326         if (!client) {
327                 ErrPrint("Failed to create a new client (%d)\n", pid);
328                 return NULL;
329         }
330
331         ret = client_rpc_init(client, handle);
332         if (ret < 0) {
333                 client = client_unref(client);
334                 ErrPrint("Failed to initialize the RPC for %d, Destroy client data %p(has to be 0x0)\n", pid, client);
335         } else {
336                 Ecore_Timer *create_timer;
337                 /*!
338                  * \note
339                  * To save the time to send reply packet to the client.
340                  */
341                 create_timer = ecore_timer_add(DELAY_TIME, created_cb, client_ref(client));
342                 if (create_timer == NULL) {
343                         ErrPrint("Failed to add a timer for client created event\n");
344                         client = client_unref(client); /* Decrease refcnt for argument */
345                         client = client_unref(client); /* Destroy client object */
346                         return NULL;
347                 }
348
349                 ret = client_set_data(client, "create,timer", create_timer);
350                 DbgPrint("Set data: %d\n", ret);
351         }
352
353         return client;
354 }
355
356 HAPI struct client_node *client_ref(struct client_node *client)
357 {
358         if (!client) {
359                 return NULL;
360         }
361
362         client->refcnt++;
363         return client;
364 }
365
366 HAPI struct client_node *client_unref(struct client_node *client)
367 {
368         if (!client) {
369                 return NULL;
370         }
371
372         if (client->refcnt == 0) {
373                 ErrPrint("Client refcnt is not managed correctly\n");
374                 return NULL;
375         }
376
377         client->refcnt--;
378         if (client->refcnt == 0) {
379                 destroy_client_data(client);
380                 client = NULL;
381         }
382
383         return client;
384 }
385
386 HAPI const int const client_refcnt(const struct client_node *client)
387 {
388         return client->refcnt;
389 }
390
391 HAPI const pid_t const client_pid(const struct client_node *client)
392 {
393         return client ? client->pid : (pid_t)-1;
394 }
395
396 HAPI struct client_node *client_find_by_pid(pid_t pid)
397 {
398         Eina_List *l;
399         struct client_node *client;
400
401         EINA_LIST_FOREACH(s_info.client_list, l, client) {
402                 if (client->pid == pid) {
403                         return client;
404                 }
405         }
406
407         return NULL;
408 }
409
410 HAPI struct client_node *client_find_by_rpc_handle(int handle)
411 {
412         Eina_List *l;
413         struct client_node *client;
414
415         if (handle <= 0) {
416                 ErrPrint("Invalid handle %d\n", handle);
417                 return NULL;
418         }
419
420         EINA_LIST_FOREACH(s_info.client_list, l, client) {
421                 if (client_rpc_handle(client) == handle) {
422                         return client;
423                 }
424         }
425
426         return NULL;
427 }
428
429 HAPI const int const client_count_paused(void)
430 {
431         return s_info.nr_of_paused_clients;
432 }
433
434 HAPI int client_is_all_paused(void)
435 {
436         DbgPrint("%d, %d\n", eina_list_count(s_info.client_list), s_info.nr_of_paused_clients);
437         return eina_list_count(s_info.client_list) == s_info.nr_of_paused_clients;
438 }
439
440 HAPI int client_count(void)
441 {
442         return eina_list_count(s_info.client_list);
443 }
444
445 HAPI struct client_node *client_deactivated_by_fault(struct client_node *client)
446 {
447         if (!client || client->faulted) {
448                 return client;
449         }
450
451         ErrPrint("Client[%p] is faulted(%d), pid(%d)\n", client, client->refcnt, client->pid);
452         client->faulted = 1;
453         client->pid = (pid_t)-1;
454
455         invoke_deactivated_cb(client);
456         client = client_destroy(client);
457         /*!
458          * \todo
459          * Who invokes this function has to care the reference counter of a client
460          * do I need to invoke the deactivated callback from here?
461          * client->pid = (pid_t)-1;
462          * slave_unref(client)
463          */
464         return client;
465 }
466
467 HAPI const int const client_is_faulted(const struct client_node *client)
468 {
469         /*!
470          * \note
471          * If the "client" is NIL, I assume that it is fault so returns TRUE(1)
472          */
473         return client ? client->faulted : 1;
474 }
475
476 HAPI void client_reset_fault(struct client_node *client)
477 {
478         if (client) {
479                 client->faulted = 0;
480         }
481 }
482
483 HAPI int client_event_callback_add(struct client_node *client, enum client_event event, int (*cb)(struct client_node *, void *), void *data)
484 {
485         struct event_item *item;
486
487         if (!cb) {
488                 ErrPrint("Invalid callback (cb == NULL)\n");
489                 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
490         }
491
492         item = malloc(sizeof(*item));
493         if (!item) {
494                 ErrPrint("Heap: %s\n", strerror(errno));
495                 return DBOX_STATUS_ERROR_OUT_OF_MEMORY;
496         }
497
498         item->cb = cb;
499         item->data = data;
500         item->deleted = 0;
501
502         /*!
503          * \note
504          * Use the eina_list_prepend API.
505          * To keep the sequence of a callback invocation.
506          *
507          * Here is an example sequence.
508          *
509          * client_event_callback_add(CALLBACK_01);
510          * client_event_callback_add(CALLBACK_02);
511          * client_event_callback_add(CALLBACK_03);
512          *
513          * Then the invoke_event_callback function will call the CALLBACKS as below sequence
514          *
515          * invoke_CALLBACK_03
516          * invoke_CALLBACK_02
517          * invoke_CALLBACK_01
518          */
519
520         switch (event) {
521         case CLIENT_EVENT_DEACTIVATE:
522                 client->event_deactivate_list = eina_list_prepend(client->event_deactivate_list, item);
523                 break;
524         case CLIENT_EVENT_ACTIVATE:
525                 client->event_activate_list = eina_list_prepend(client->event_activate_list, item);
526                 break;
527         default:
528                 DbgFree(item);
529                 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
530         }
531
532         return DBOX_STATUS_ERROR_NONE;
533 }
534
535 HAPI int client_event_callback_del(struct client_node *client, enum client_event event, int (*cb)(struct client_node *, void *), void *data)
536 {
537         struct event_item *item;
538         Eina_List *l;
539         Eina_List *n;
540
541         if (!cb) {
542                 ErrPrint("Invalid callback (cb == NULL)\n");
543                 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
544         }
545
546         switch (event) {
547         case CLIENT_EVENT_DEACTIVATE:
548                 EINA_LIST_FOREACH_SAFE(client->event_deactivate_list, l, n, item) {
549                         if (item->cb == cb && item->data == data) {
550                                 if (client->in_event_process & CLIENT_EVENT_PROCESS_DEACTIVATE) {
551                                         item->deleted = 1;
552                                 } else {
553                                         client->event_deactivate_list = eina_list_remove(client->event_deactivate_list, item);
554                                         DbgFree(item);
555                                 }
556                                 return DBOX_STATUS_ERROR_NONE;
557                         }
558                 }
559                 break;
560
561         case CLIENT_EVENT_ACTIVATE:
562                 EINA_LIST_FOREACH_SAFE(client->event_activate_list, l, n, item) {
563                         if (item->cb == cb && item->data == data) {
564                                 if (client->in_event_process & CLIENT_EVENT_PROCESS_ACTIVATE) {
565                                         item->deleted = 1;
566                                 } else {
567                                         client->event_activate_list = eina_list_remove(client->event_activate_list, item);
568                                         DbgFree(item);
569                                 }
570                                 return DBOX_STATUS_ERROR_NONE;
571                         }
572                 }
573                 break;
574
575         default:
576                 ErrPrint("Invalid event\n");
577                 break;
578         }
579
580         return DBOX_STATUS_ERROR_NOT_EXIST;
581 }
582
583 HAPI int client_set_data(struct client_node *client, const char *tag, void *data)
584 {
585         struct data_item *item;
586
587         item = calloc(1, sizeof(*item));
588         if (!item) {
589                 ErrPrint("Heap: %s\n", strerror(errno));
590                 return DBOX_STATUS_ERROR_OUT_OF_MEMORY;
591         }
592
593         item->tag = strdup(tag);
594         if (!item->tag) {
595                 ErrPrint("Heap: %s\n", strerror(errno));
596                 DbgFree(item);
597                 return DBOX_STATUS_ERROR_OUT_OF_MEMORY;
598         }
599
600         item->data = data;
601
602         client->data_list = eina_list_append(client->data_list, item);
603         return DBOX_STATUS_ERROR_NONE;
604 }
605
606 HAPI void *client_data(struct client_node *client, const char *tag)
607 {
608         Eina_List *l;
609         struct data_item *item;
610
611         EINA_LIST_FOREACH(client->data_list, l, item) {
612                 if (!strcmp(item->tag, tag)) {
613                         return item->data;
614                 }
615         }
616
617         return NULL;
618 }
619
620 HAPI void *client_del_data(struct client_node *client, const char *tag)
621 {
622         Eina_List *l;
623         Eina_List *n;
624         struct data_item *item;
625
626         EINA_LIST_FOREACH_SAFE(client->data_list, l, n, item) {
627                 if (!strcmp(item->tag, tag)) {
628                         void *data;
629                         client->data_list = eina_list_remove(client->data_list, item);
630                         data = item->data;
631                         DbgFree(item->tag);
632                         DbgFree(item);
633                         return data;
634                 }
635         }
636
637         return NULL;
638 }
639
640 HAPI void client_paused(struct client_node *client)
641 {
642         if (client->paused) {
643                 return;
644         }
645
646         client->paused = 1;
647         s_info.nr_of_paused_clients++;
648 }
649
650 HAPI void client_resumed(struct client_node *client)
651 {
652         if (client->paused == 0) {
653                 return;
654         }
655
656         client->paused = 0;
657         s_info.nr_of_paused_clients--;
658 }
659
660 HAPI int client_init(void)
661 {
662         return DBOX_STATUS_ERROR_NONE;
663 }
664
665 HAPI void client_fini(void)
666 {
667         struct global_event_item *handler;
668         struct client_node *client;
669         Eina_List *l;
670         Eina_List *n;
671
672         EINA_LIST_FOREACH_SAFE(s_info.client_list, l, n, client) {
673                 (void)client_destroy(client);
674         }
675
676         EINA_LIST_FREE(s_info.create_event_list, handler) {
677                 DbgFree(handler);
678         }
679
680         EINA_LIST_FREE(s_info.destroy_event_list, handler) {
681                 DbgFree(handler);
682         }
683 }
684
685 HAPI int client_global_event_handler_add(enum client_global_event event_type, int (*cb)(struct client_node *client, void *data), void *data)
686 {
687         struct global_event_item *handler;
688
689         handler = malloc(sizeof(*handler));
690         if (!handler) {
691                 ErrPrint("Heap: %s\n", strerror(errno));
692                 return DBOX_STATUS_ERROR_OUT_OF_MEMORY;
693         }
694
695         handler->cbdata = data;
696         handler->cb = cb;
697         handler->deleted = 0;
698
699         switch (event_type) {
700         case CLIENT_GLOBAL_EVENT_CREATE:
701                 s_info.create_event_list = eina_list_prepend(s_info.create_event_list, handler);
702                 break;
703         case CLIENT_GLOBAL_EVENT_DESTROY:
704                 s_info.destroy_event_list = eina_list_prepend(s_info.destroy_event_list, handler);
705                 break;
706         default:
707                 DbgFree(handler);
708                 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
709         }
710
711         return DBOX_STATUS_ERROR_NONE;
712 }
713
714 HAPI int client_global_event_handler_del(enum client_global_event event_type, int (*cb)(struct client_node *, void *), void *data)
715 {
716         Eina_List *l;
717         Eina_List *n;
718         struct global_event_item *item;
719
720         switch (event_type) {
721         case CLIENT_GLOBAL_EVENT_CREATE:
722                 EINA_LIST_FOREACH_SAFE(s_info.create_event_list, l, n, item) {
723                         if (item->cb == cb && item->cbdata == data) {
724                                 if (s_info.in_event_process & GLOBAL_EVENT_PROCESS_CREATE) {
725                                         item->deleted = 1;
726                                 } else {
727                                         s_info.create_event_list = eina_list_remove(s_info.create_event_list, item);
728                                         DbgFree(item);
729                                 }
730                                 return DBOX_STATUS_ERROR_NONE;
731                         }
732                 }
733                 break;
734         case CLIENT_GLOBAL_EVENT_DESTROY:
735                 EINA_LIST_FOREACH_SAFE(s_info.destroy_event_list, l, n, item) {
736                         if (item->cb == cb && item->cbdata == data) {
737                                 if (s_info.in_event_process & GLOBAL_EVENT_PROCESS_DESTROY) {
738                                         item->deleted = 1;
739                                 } else {
740                                         s_info.destroy_event_list = eina_list_remove(s_info.destroy_event_list, item);
741                                         DbgFree(item);
742                                 }
743                                 return DBOX_STATUS_ERROR_NONE;
744                         }
745                 }
746                 break;
747         default:
748                 break;
749         }
750
751         return DBOX_STATUS_ERROR_NOT_EXIST;
752 }
753
754 HAPI int client_subscribe(struct client_node *client, const char *cluster, const char *category)
755 {
756         struct subscribe_item *item;
757
758         item = malloc(sizeof(*item));
759         if (!item) {
760                 ErrPrint("Heap: %s\n", strerror(errno));
761                 return DBOX_STATUS_ERROR_OUT_OF_MEMORY;
762         }
763
764         item->cluster = strdup(cluster);
765         if (!item->cluster) {
766                 ErrPrint("Heap: %s\n", strerror(errno));
767                 DbgFree(item);
768                 return DBOX_STATUS_ERROR_OUT_OF_MEMORY;
769         }
770
771         item->category = strdup(category);
772         if (!item->category) {
773                 ErrPrint("Heap: %s\n", strerror(errno));
774                 DbgFree(item->cluster);
775                 DbgFree(item);
776                 return DBOX_STATUS_ERROR_OUT_OF_MEMORY;
777         }
778
779         client->subscribe_list = eina_list_append(client->subscribe_list, item);
780         return DBOX_STATUS_ERROR_NONE;
781 }
782
783 HAPI int client_unsubscribe(struct client_node *client, const char *cluster, const char *category)
784 {
785         struct subscribe_item *item;
786         Eina_List *l;
787         Eina_List *n;
788
789         EINA_LIST_FOREACH_SAFE(client->subscribe_list, l, n, item) {
790                 if (!strcasecmp(cluster, item->cluster) && !strcasecmp(category, item->category)) {
791                         client->subscribe_list = eina_list_remove(client->subscribe_list, item);
792                         DbgFree(item->cluster);
793                         DbgFree(item->category);
794                         DbgFree(item);
795                         return DBOX_STATUS_ERROR_NONE;
796                 }
797         }
798
799         return DBOX_STATUS_ERROR_NOT_EXIST;
800 }
801
802 HAPI int client_is_subscribed(struct client_node *client, const char *cluster, const char *category)
803 {
804         struct subscribe_item *item;
805         Eina_List *l;
806
807         EINA_LIST_FOREACH(client->subscribe_list, l, item) {
808                 if (!strcmp(item->cluster, "*")) {
809                         return 1;
810                 }
811
812                 if (strcasecmp(item->cluster, cluster)) {
813                         continue;
814                 }
815
816                 if (!strcmp(item->category, "*")) {
817                         return 1;
818                 }
819
820                 if (!strcasecmp(item->category, category)) {
821                         return 1;
822                 }
823         }
824
825         return 0;
826 }
827
828 HAPI int client_browse_list(const char *cluster, const char *category, int (*cb)(struct client_node *client, void *data), void *data)
829 {
830         Eina_List *l;
831         struct client_node *client;
832         int cnt;
833
834         if (!cb || !cluster || !category) {
835                 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
836         }
837
838         cnt = 0;
839         EINA_LIST_FOREACH(s_info.client_list, l, client) {
840                 if (!client_is_subscribed(client, cluster, category)) {
841                         continue;
842                 }
843
844                 if (cb(client, data) < 0) {
845                         return DBOX_STATUS_ERROR_CANCEL;
846                 }
847
848                 cnt++;
849         }
850
851         return cnt;
852 }
853
854 HAPI int client_nr_of_subscriber(const char *cluster, const char *category)
855 {
856         Eina_List *l;
857         struct client_node *client;
858         int cnt;
859
860         cnt = 0;
861         EINA_LIST_FOREACH(s_info.client_list, l, client) {
862                 cnt += !!client_is_subscribed(client, cluster, category);
863         }
864
865         return cnt;
866 }
867
868 HAPI int client_broadcast(struct inst_info *inst, struct packet *packet)
869 {
870         Eina_List *l;
871         Eina_List *list;
872         struct client_node *client;
873
874         list = inst ? instance_client_list(inst) : s_info.client_list;
875         EINA_LIST_FOREACH(list, l, client) {
876                 if (client_pid(client) == -1) {
877                         ErrPrint("Client[%p] has PID[%d]\n", client, client_pid(client));
878                         continue;
879                 }
880
881                 (void)client_rpc_async_request(client, packet_ref(packet));
882         }
883
884         packet_unref(packet);
885         return DBOX_STATUS_ERROR_NONE;
886 }
887
888 HAPI const char *client_direct_addr(const struct client_node *client)
889 {
890         return client ? client->direct_addr : NULL;
891 }
892
893 /* End of a file */