2 * Copyright 2013 Samsung Electronics Co., Ltd
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
8 * http://floralicense.org/license/
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.
20 #include <sys/types.h>
23 #include <sys/smack.h>
30 #include <dynamicbox_errno.h>
32 #include "client_life.h"
34 #include "client_rpc.h"
37 #include "slave_life.h"
44 Eina_List *client_list;
45 int nr_of_paused_clients;
47 enum global_event_process {
48 GLOBAL_EVENT_PROCESS_IDLE = 0x00,
49 GLOBAL_EVENT_PROCESS_CREATE = 0x01,
50 GLOBAL_EVENT_PROCESS_DESTROY = 0x02
53 Eina_List *create_event_list;
54 Eina_List *destroy_event_list;
58 .nr_of_paused_clients = 0,
59 .in_event_process = GLOBAL_EVENT_PROCESS_IDLE,
60 .create_event_list = NULL,
61 .destroy_event_list = NULL,
64 struct subscribe_item {
69 struct global_event_item {
71 int (*cb)(struct client_node *client, void *data);
77 int (*cb)(struct client_node *, void *);
92 enum client_event_process {
93 CLIENT_EVENT_PROCESS_IDLE = 0x00,
94 CLIENT_EVENT_PROCESS_DEACTIVATE = 0x01,
95 CLIENT_EVENT_PROCESS_ACTIVATE = 0x02
97 Eina_List *event_deactivate_list;
98 Eina_List *event_activate_list;
100 Eina_List *data_list;
101 Eina_List *subscribe_list;
107 static inline void invoke_global_destroyed_cb(struct client_node *client)
111 struct global_event_item *item;
113 s_info.in_event_process |= GLOBAL_EVENT_PROCESS_DESTROY;
114 EINA_LIST_FOREACH_SAFE(s_info.destroy_event_list, l, n, item) {
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
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);
128 s_info.in_event_process &= ~GLOBAL_EVENT_PROCESS_DESTROY;
131 static inline void invoke_global_created_cb(struct client_node *client)
135 struct global_event_item *item;
137 s_info.in_event_process |= GLOBAL_EVENT_PROCESS_CREATE;
138 EINA_LIST_FOREACH_SAFE(s_info.create_event_list, l, n, item) {
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
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);
153 s_info.in_event_process &= ~GLOBAL_EVENT_PROCESS_CREATE;
156 static inline void invoke_deactivated_cb(struct client_node *client)
158 struct event_item *item;
162 client->in_event_process |= CLIENT_EVENT_PROCESS_DEACTIVATE;
163 EINA_LIST_FOREACH_SAFE(client->event_deactivate_list, l, n, item) {
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
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);
178 client->in_event_process &= ~CLIENT_EVENT_PROCESS_DEACTIVATE;
181 static inline void invoke_activated_cb(struct client_node *client)
183 struct event_item *item;
187 client->in_event_process |= CLIENT_EVENT_PROCESS_ACTIVATE;
188 EINA_LIST_FOREACH_SAFE(client->event_activate_list, l, n, item) {
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
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);
203 client->in_event_process &= ~CLIENT_EVENT_PROCESS_ACTIVATE;
206 static inline void destroy_client_data(struct client_node *client)
208 struct event_item *event;
209 struct data_item *data;
210 struct subscribe_item *item;
213 timer = client_del_data(client, "create,timer");
215 ecore_timer_del(timer);
218 DbgPrint("Destroy client: %p\n", client);
220 invoke_global_destroyed_cb(client);
221 client_rpc_fini(client); /*!< Finalize the RPC after invoke destroy callbacks */
223 EINA_LIST_FREE(client->data_list, data) {
224 DbgPrint("Tag is not cleared (%s)\n", data->tag);
229 EINA_LIST_FREE(client->event_deactivate_list, event) {
233 EINA_LIST_FREE(client->subscribe_list, item) {
234 DbgFree(item->cluster);
235 DbgFree(item->category);
239 if (client->paused) {
240 s_info.nr_of_paused_clients--;
243 if (client->direct_addr) {
244 (void)unlink(client->direct_addr);
245 DbgFree(client->direct_addr);
248 s_info.client_list = eina_list_remove(s_info.client_list, client);
253 * If there is any changes of clients,
254 * We should check the pause/resume states again.
256 xmonitor_handle_state_changes();
259 static inline struct client_node *create_client_data(pid_t pid, const char *direct_addr)
261 struct client_node *client;
263 client = calloc(1, sizeof(*client));
265 ErrPrint("Heap: %s\n", strerror(errno));
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);
279 s_info.client_list = eina_list_append(s_info.client_list, client);
283 * Right after create a client ADT,
284 * We assume that the client is paused.
286 client_paused(client);
287 xmonitor_handle_state_changes();
291 static Eina_Bool created_cb(void *data)
293 (void)client_del_data(data, "create,timer");
295 invoke_global_created_cb(data);
296 invoke_activated_cb(data);
299 * Client PAUSE/RESUME event must has to be sent after created event.
301 xmonitor_update_state(client_pid(data));
303 (void)client_unref(data);
304 return ECORE_CALLBACK_CANCEL;
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
314 HAPI struct client_node *client_create(pid_t pid, int handle, const char *direct_addr)
316 struct client_node *client;
319 client = client_find_by_rpc_handle(handle);
321 ErrPrint("Client %d(%d) is already exists\n", pid, handle);
325 client = create_client_data(pid, direct_addr);
327 ErrPrint("Failed to create a new client (%d)\n", pid);
331 ret = client_rpc_init(client, handle);
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);
336 Ecore_Timer *create_timer;
339 * To save the time to send reply packet to the client.
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 */
349 ret = client_set_data(client, "create,timer", create_timer);
350 DbgPrint("Set data: %d\n", ret);
356 HAPI struct client_node *client_ref(struct client_node *client)
366 HAPI struct client_node *client_unref(struct client_node *client)
372 if (client->refcnt == 0) {
373 ErrPrint("Client refcnt is not managed correctly\n");
378 if (client->refcnt == 0) {
379 destroy_client_data(client);
386 HAPI const int const client_refcnt(const struct client_node *client)
388 return client->refcnt;
391 HAPI const pid_t const client_pid(const struct client_node *client)
393 return client ? client->pid : (pid_t)-1;
396 HAPI struct client_node *client_find_by_pid(pid_t pid)
399 struct client_node *client;
401 EINA_LIST_FOREACH(s_info.client_list, l, client) {
402 if (client->pid == pid) {
410 HAPI struct client_node *client_find_by_rpc_handle(int handle)
413 struct client_node *client;
416 ErrPrint("Invalid handle %d\n", handle);
420 EINA_LIST_FOREACH(s_info.client_list, l, client) {
421 if (client_rpc_handle(client) == handle) {
429 HAPI const int const client_count_paused(void)
431 return s_info.nr_of_paused_clients;
434 HAPI int client_is_all_paused(void)
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;
440 HAPI int client_count(void)
442 return eina_list_count(s_info.client_list);
445 HAPI struct client_node *client_deactivated_by_fault(struct client_node *client)
447 if (!client || client->faulted) {
451 ErrPrint("Client[%p] is faulted(%d), pid(%d)\n", client, client->refcnt, client->pid);
453 client->pid = (pid_t)-1;
455 invoke_deactivated_cb(client);
456 client = client_destroy(client);
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)
467 HAPI const int const client_is_faulted(const struct client_node *client)
471 * If the "client" is NIL, I assume that it is fault so returns TRUE(1)
473 return client ? client->faulted : 1;
476 HAPI void client_reset_fault(struct client_node *client)
483 HAPI int client_event_callback_add(struct client_node *client, enum client_event event, int (*cb)(struct client_node *, void *), void *data)
485 struct event_item *item;
488 ErrPrint("Invalid callback (cb == NULL)\n");
489 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
492 item = malloc(sizeof(*item));
494 ErrPrint("Heap: %s\n", strerror(errno));
495 return DBOX_STATUS_ERROR_OUT_OF_MEMORY;
504 * Use the eina_list_prepend API.
505 * To keep the sequence of a callback invocation.
507 * Here is an example sequence.
509 * client_event_callback_add(CALLBACK_01);
510 * client_event_callback_add(CALLBACK_02);
511 * client_event_callback_add(CALLBACK_03);
513 * Then the invoke_event_callback function will call the CALLBACKS as below sequence
521 case CLIENT_EVENT_DEACTIVATE:
522 client->event_deactivate_list = eina_list_prepend(client->event_deactivate_list, item);
524 case CLIENT_EVENT_ACTIVATE:
525 client->event_activate_list = eina_list_prepend(client->event_activate_list, item);
529 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
532 return DBOX_STATUS_ERROR_NONE;
535 HAPI int client_event_callback_del(struct client_node *client, enum client_event event, int (*cb)(struct client_node *, void *), void *data)
537 struct event_item *item;
542 ErrPrint("Invalid callback (cb == NULL)\n");
543 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
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) {
553 client->event_deactivate_list = eina_list_remove(client->event_deactivate_list, item);
556 return DBOX_STATUS_ERROR_NONE;
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) {
567 client->event_activate_list = eina_list_remove(client->event_activate_list, item);
570 return DBOX_STATUS_ERROR_NONE;
576 ErrPrint("Invalid event\n");
580 return DBOX_STATUS_ERROR_NOT_EXIST;
583 HAPI int client_set_data(struct client_node *client, const char *tag, void *data)
585 struct data_item *item;
587 item = calloc(1, sizeof(*item));
589 ErrPrint("Heap: %s\n", strerror(errno));
590 return DBOX_STATUS_ERROR_OUT_OF_MEMORY;
593 item->tag = strdup(tag);
595 ErrPrint("Heap: %s\n", strerror(errno));
597 return DBOX_STATUS_ERROR_OUT_OF_MEMORY;
602 client->data_list = eina_list_append(client->data_list, item);
603 return DBOX_STATUS_ERROR_NONE;
606 HAPI void *client_data(struct client_node *client, const char *tag)
609 struct data_item *item;
611 EINA_LIST_FOREACH(client->data_list, l, item) {
612 if (!strcmp(item->tag, tag)) {
620 HAPI void *client_del_data(struct client_node *client, const char *tag)
624 struct data_item *item;
626 EINA_LIST_FOREACH_SAFE(client->data_list, l, n, item) {
627 if (!strcmp(item->tag, tag)) {
629 client->data_list = eina_list_remove(client->data_list, item);
640 HAPI void client_paused(struct client_node *client)
642 if (client->paused) {
647 s_info.nr_of_paused_clients++;
650 HAPI void client_resumed(struct client_node *client)
652 if (client->paused == 0) {
657 s_info.nr_of_paused_clients--;
660 HAPI int client_init(void)
662 return DBOX_STATUS_ERROR_NONE;
665 HAPI void client_fini(void)
667 struct global_event_item *handler;
668 struct client_node *client;
672 EINA_LIST_FOREACH_SAFE(s_info.client_list, l, n, client) {
673 (void)client_destroy(client);
676 EINA_LIST_FREE(s_info.create_event_list, handler) {
680 EINA_LIST_FREE(s_info.destroy_event_list, handler) {
685 HAPI int client_global_event_handler_add(enum client_global_event event_type, int (*cb)(struct client_node *client, void *data), void *data)
687 struct global_event_item *handler;
689 handler = malloc(sizeof(*handler));
691 ErrPrint("Heap: %s\n", strerror(errno));
692 return DBOX_STATUS_ERROR_OUT_OF_MEMORY;
695 handler->cbdata = data;
697 handler->deleted = 0;
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);
703 case CLIENT_GLOBAL_EVENT_DESTROY:
704 s_info.destroy_event_list = eina_list_prepend(s_info.destroy_event_list, handler);
708 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
711 return DBOX_STATUS_ERROR_NONE;
714 HAPI int client_global_event_handler_del(enum client_global_event event_type, int (*cb)(struct client_node *, void *), void *data)
718 struct global_event_item *item;
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) {
727 s_info.create_event_list = eina_list_remove(s_info.create_event_list, item);
730 return DBOX_STATUS_ERROR_NONE;
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) {
740 s_info.destroy_event_list = eina_list_remove(s_info.destroy_event_list, item);
743 return DBOX_STATUS_ERROR_NONE;
751 return DBOX_STATUS_ERROR_NOT_EXIST;
754 HAPI int client_subscribe(struct client_node *client, const char *cluster, const char *category)
756 struct subscribe_item *item;
758 item = malloc(sizeof(*item));
760 ErrPrint("Heap: %s\n", strerror(errno));
761 return DBOX_STATUS_ERROR_OUT_OF_MEMORY;
764 item->cluster = strdup(cluster);
765 if (!item->cluster) {
766 ErrPrint("Heap: %s\n", strerror(errno));
768 return DBOX_STATUS_ERROR_OUT_OF_MEMORY;
771 item->category = strdup(category);
772 if (!item->category) {
773 ErrPrint("Heap: %s\n", strerror(errno));
774 DbgFree(item->cluster);
776 return DBOX_STATUS_ERROR_OUT_OF_MEMORY;
779 client->subscribe_list = eina_list_append(client->subscribe_list, item);
780 return DBOX_STATUS_ERROR_NONE;
783 HAPI int client_unsubscribe(struct client_node *client, const char *cluster, const char *category)
785 struct subscribe_item *item;
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);
795 return DBOX_STATUS_ERROR_NONE;
799 return DBOX_STATUS_ERROR_NOT_EXIST;
802 HAPI int client_is_subscribed(struct client_node *client, const char *cluster, const char *category)
804 struct subscribe_item *item;
807 EINA_LIST_FOREACH(client->subscribe_list, l, item) {
808 if (!strcmp(item->cluster, "*")) {
812 if (strcasecmp(item->cluster, cluster)) {
816 if (!strcmp(item->category, "*")) {
820 if (!strcasecmp(item->category, category)) {
828 HAPI int client_browse_list(const char *cluster, const char *category, int (*cb)(struct client_node *client, void *data), void *data)
831 struct client_node *client;
834 if (!cb || !cluster || !category) {
835 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
839 EINA_LIST_FOREACH(s_info.client_list, l, client) {
840 if (!client_is_subscribed(client, cluster, category)) {
844 if (cb(client, data) < 0) {
845 return DBOX_STATUS_ERROR_CANCEL;
854 HAPI int client_nr_of_subscriber(const char *cluster, const char *category)
857 struct client_node *client;
861 EINA_LIST_FOREACH(s_info.client_list, l, client) {
862 cnt += !!client_is_subscribed(client, cluster, category);
868 HAPI int client_broadcast(struct inst_info *inst, struct packet *packet)
872 struct client_node *client;
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));
881 (void)client_rpc_async_request(client, packet_ref(packet));
884 packet_unref(packet);
885 return DBOX_STATUS_ERROR_NONE;
888 HAPI const char *client_direct_addr(const struct client_node *client)
890 return client ? client->direct_addr : NULL;