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.
25 #include <livebox-errno.h>
27 #include "client_life.h"
29 #include "client_rpc.h"
32 #include "slave_life.h"
39 Eina_List *client_list;
40 int nr_of_paused_clients;
42 enum global_event_process {
43 GLOBAL_EVENT_PROCESS_IDLE = 0x00,
44 GLOBAL_EVENT_PROCESS_CREATE = 0x01,
45 GLOBAL_EVENT_PROCESS_DESTROY = 0x02
48 Eina_List *create_event_list;
49 Eina_List *destroy_event_list;
53 .nr_of_paused_clients = 0,
54 .in_event_process = GLOBAL_EVENT_PROCESS_IDLE,
55 .create_event_list = NULL,
56 .destroy_event_list = NULL,
59 struct subscribe_item {
64 struct global_event_item {
66 int (*cb)(struct client_node *client, void *data);
72 int (*cb)(struct client_node *, void *);
87 enum client_event_process {
88 CLIENT_EVENT_PROCESS_IDLE = 0x00,
89 CLIENT_EVENT_PROCESS_DEACTIVATE = 0x01,
90 CLIENT_EVENT_PROCESS_ACTIVATE = 0x02
92 Eina_List *event_deactivate_list;
93 Eina_List *event_activate_list;
96 Eina_List *subscribe_list;
101 static inline void invoke_global_destroyed_cb(struct client_node *client)
105 struct global_event_item *item;
107 s_info.in_event_process |= GLOBAL_EVENT_PROCESS_DESTROY;
108 EINA_LIST_FOREACH_SAFE(s_info.destroy_event_list, l, n, item) {
111 * item->deleted will be checked, so if it is deleted, remove item from the list
112 * The second, if the first routine takes false path,
113 * item->cb will be called, if it returns negative value, remove item from the list
114 * The third, if the second routine takes false path,
115 * Check the item->deleted again, so if it is turnned on, remove item from the list
117 if (item->deleted || item->cb(client, item->cbdata) < 0 || item->deleted) {
118 s_info.destroy_event_list = eina_list_remove(s_info.destroy_event_list, item);
122 s_info.in_event_process &= ~GLOBAL_EVENT_PROCESS_DESTROY;
125 static inline void invoke_global_created_cb(struct client_node *client)
129 struct global_event_item *item;
131 s_info.in_event_process |= GLOBAL_EVENT_PROCESS_CREATE;
132 EINA_LIST_FOREACH_SAFE(s_info.create_event_list, l, n, item) {
135 * item->deleted will be checked, so if it is deleted, remove item from the list
136 * The second, if the first routine takes false path,
137 * item->cb will be called, if it returns negative value, remove item from the list
138 * The third, if the second routine takes false path,
139 * Check the item->deleted again, so if it is turnned on, remove item from the list
142 if (item->deleted || item->cb(client, item->cbdata) < 0 || item->deleted) {
143 s_info.create_event_list = eina_list_remove(s_info.create_event_list, item);
147 s_info.in_event_process &= ~GLOBAL_EVENT_PROCESS_CREATE;
150 static inline void invoke_deactivated_cb(struct client_node *client)
152 struct event_item *item;
156 client->in_event_process |= CLIENT_EVENT_PROCESS_DEACTIVATE;
157 EINA_LIST_FOREACH_SAFE(client->event_deactivate_list, l, n, item) {
160 * item->deleted will be checked, so if it is deleted, remove item from the list
161 * The second, if the first routine takes false path,
162 * item->cb will be called, if it returns negative value, remove item from the list
163 * The third, if the second routine takes false path,
164 * Check the item->deleted again, so if it is turnned on, remove item from the list
167 if (item->deleted || item->cb(client, item->data) < 0 || item->deleted) {
168 client->event_deactivate_list = eina_list_remove(client->event_deactivate_list, item);
172 client->in_event_process &= ~CLIENT_EVENT_PROCESS_DEACTIVATE;
175 static inline void invoke_activated_cb(struct client_node *client)
177 struct event_item *item;
181 client->in_event_process |= CLIENT_EVENT_PROCESS_ACTIVATE;
182 EINA_LIST_FOREACH_SAFE(client->event_activate_list, l, n, item) {
185 * item->deleted will be checked, so if it is deleted, remove item from the list
186 * The second, if the first routine takes false path,
187 * item->cb will be called, if it returns negative value, remove item from the list
188 * The third, if the second routine takes false path,
189 * Check the item->deleted again, so if it is turnned on, remove item from the list
192 if (item->deleted || item->cb(client, item->data) < 0 || item->deleted) {
193 client->event_activate_list = eina_list_remove(client->event_activate_list, item);
197 client->in_event_process &= ~CLIENT_EVENT_PROCESS_ACTIVATE;
200 static inline void destroy_client_data(struct client_node *client)
202 struct event_item *event;
203 struct data_item *data;
204 struct subscribe_item *item;
207 timer = client_del_data(client, "create,timer");
209 ecore_timer_del(timer);
212 DbgPrint("Destroy client: %p\n", client);
214 invoke_global_destroyed_cb(client);
215 client_rpc_fini(client); /*!< Finalize the RPC after invoke destroy callbacks */
217 EINA_LIST_FREE(client->data_list, data) {
218 DbgPrint("Tag is not cleared (%s)\n", data->tag);
223 EINA_LIST_FREE(client->event_deactivate_list, event) {
227 EINA_LIST_FREE(client->subscribe_list, item) {
228 DbgFree(item->cluster);
229 DbgFree(item->category);
233 if (client->paused) {
234 s_info.nr_of_paused_clients--;
237 s_info.client_list = eina_list_remove(s_info.client_list, client);
242 * If there is any changes of clients,
243 * We should check the pause/resume states again.
245 xmonitor_handle_state_changes();
248 static inline struct client_node *create_client_data(pid_t pid)
250 struct client_node *client;
252 client = calloc(1, sizeof(*client));
254 ErrPrint("Heap: %s\n", strerror(errno));
261 s_info.client_list = eina_list_append(s_info.client_list, client);
265 * Right after create a client ADT,
266 * We assume that the client is paused.
268 client_paused(client);
269 xmonitor_handle_state_changes();
273 static Eina_Bool created_cb(void *data)
275 (void)client_del_data(data, "create,timer");
277 invoke_global_created_cb(data);
278 invoke_activated_cb(data);
281 * Client PAUSE/RESUME event must has to be sent after created event.
283 xmonitor_update_state(client_pid(data));
285 (void)client_unref(data);
286 return ECORE_CALLBACK_CANCEL;
291 * Noramlly, client ADT is created when it send the "acquire" packet.
292 * It means we have the handle for communicating with the client already,
293 * So we just create its ADT in this function.
294 * And invoke the global created event & activated event callbacks
296 HAPI struct client_node *client_create(pid_t pid, int handle)
298 struct client_node *client;
301 client = client_find_by_rpc_handle(handle);
303 ErrPrint("Client %d(%d) is already exists\n", pid, handle);
307 client = create_client_data(pid);
309 ErrPrint("Failed to create a new client (%d)\n", pid);
313 ret = client_rpc_init(client, handle);
315 client = client_unref(client);
316 ErrPrint("Failed to initialize the RPC for %d, Destroy client data %p(has to be 0x0)\n", pid, client);
318 Ecore_Timer *create_timer;
321 * To save the time to send reply packet to the client.
323 create_timer = ecore_timer_add(DELAY_TIME, created_cb, client_ref(client));
324 if (create_timer == NULL) {
325 ErrPrint("Failed to add a timer for client created event\n");
326 client = client_unref(client); /* Decrease refcnt for argument */
327 client = client_unref(client); /* Destroy client object */
331 ret = client_set_data(client, "create,timer", create_timer);
332 DbgPrint("Set data: %d\n", ret);
338 HAPI struct client_node *client_ref(struct client_node *client)
348 HAPI struct client_node *client_unref(struct client_node *client)
354 if (client->refcnt == 0) {
355 ErrPrint("Client refcnt is not managed correctly\n");
360 if (client->refcnt == 0) {
361 destroy_client_data(client);
368 HAPI const int const client_refcnt(const struct client_node *client)
370 return client->refcnt;
373 HAPI const pid_t const client_pid(const struct client_node *client)
375 return client ? client->pid : (pid_t)-1;
378 HAPI struct client_node *client_find_by_pid(pid_t pid)
381 struct client_node *client;
383 EINA_LIST_FOREACH(s_info.client_list, l, client) {
384 if (client->pid == pid) {
392 HAPI struct client_node *client_find_by_rpc_handle(int handle)
395 struct client_node *client;
398 ErrPrint("Invalid handle %d\n", handle);
402 EINA_LIST_FOREACH(s_info.client_list, l, client) {
403 if (client_rpc_handle(client) == handle) {
411 HAPI const int const client_count_paused(void)
413 return s_info.nr_of_paused_clients;
416 HAPI int client_is_all_paused(void)
418 DbgPrint("%d, %d\n", eina_list_count(s_info.client_list), s_info.nr_of_paused_clients);
419 return eina_list_count(s_info.client_list) == s_info.nr_of_paused_clients;
422 HAPI int client_count(void)
424 return eina_list_count(s_info.client_list);
427 HAPI struct client_node *client_deactivated_by_fault(struct client_node *client)
429 if (!client || client->faulted) {
433 ErrPrint("Client[%p] is faulted(%d), pid(%d)\n", client, client->refcnt, client->pid);
435 client->pid = (pid_t)-1;
437 invoke_deactivated_cb(client);
438 client = client_destroy(client);
441 * Who invokes this function has to care the reference counter of a client
442 * do I need to invoke the deactivated callback from here?
443 * client->pid = (pid_t)-1;
444 * slave_unref(client)
449 HAPI const int const client_is_faulted(const struct client_node *client)
453 * If the "client" is NIL, I assume that it is fault so returns TRUE(1)
455 return client ? client->faulted : 1;
458 HAPI void client_reset_fault(struct client_node *client)
465 HAPI int client_event_callback_add(struct client_node *client, enum client_event event, int (*cb)(struct client_node *, void *), void *data)
467 struct event_item *item;
470 ErrPrint("Invalid callback (cb == NULL)\n");
471 return LB_STATUS_ERROR_INVALID;
474 item = malloc(sizeof(*item));
476 ErrPrint("Heap: %s\n", strerror(errno));
477 return LB_STATUS_ERROR_MEMORY;
486 * Use the eina_list_prepend API.
487 * To keep the sequence of a callback invocation.
489 * Here is an example sequence.
491 * client_event_callback_add(CALLBACK_01);
492 * client_event_callback_add(CALLBACK_02);
493 * client_event_callback_add(CALLBACK_03);
495 * Then the invoke_event_callback function will call the CALLBACKS as below sequence
503 case CLIENT_EVENT_DEACTIVATE:
504 client->event_deactivate_list = eina_list_prepend(client->event_deactivate_list, item);
506 case CLIENT_EVENT_ACTIVATE:
507 client->event_activate_list = eina_list_prepend(client->event_activate_list, item);
511 return LB_STATUS_ERROR_INVALID;
514 return LB_STATUS_SUCCESS;
517 HAPI int client_event_callback_del(struct client_node *client, enum client_event event, int (*cb)(struct client_node *, void *), void *data)
519 struct event_item *item;
524 ErrPrint("Invalid callback (cb == NULL)\n");
525 return LB_STATUS_ERROR_INVALID;
529 case CLIENT_EVENT_DEACTIVATE:
530 EINA_LIST_FOREACH_SAFE(client->event_deactivate_list, l, n, item) {
531 if (item->cb == cb && item->data == data) {
532 if (client->in_event_process & CLIENT_EVENT_PROCESS_DEACTIVATE) {
535 client->event_deactivate_list = eina_list_remove(client->event_deactivate_list, item);
538 return LB_STATUS_SUCCESS;
543 case CLIENT_EVENT_ACTIVATE:
544 EINA_LIST_FOREACH_SAFE(client->event_activate_list, l, n, item) {
545 if (item->cb == cb && item->data == data) {
546 if (client->in_event_process & CLIENT_EVENT_PROCESS_ACTIVATE) {
549 client->event_activate_list = eina_list_remove(client->event_activate_list, item);
552 return LB_STATUS_SUCCESS;
558 ErrPrint("Invalid event\n");
562 return LB_STATUS_ERROR_NOT_EXIST;
565 HAPI int client_set_data(struct client_node *client, const char *tag, void *data)
567 struct data_item *item;
569 item = calloc(1, sizeof(*item));
571 ErrPrint("Heap: %s\n", strerror(errno));
572 return LB_STATUS_ERROR_MEMORY;
575 item->tag = strdup(tag);
577 ErrPrint("Heap: %s\n", strerror(errno));
579 return LB_STATUS_ERROR_MEMORY;
584 client->data_list = eina_list_append(client->data_list, item);
585 return LB_STATUS_SUCCESS;
588 HAPI void *client_data(struct client_node *client, const char *tag)
591 struct data_item *item;
593 EINA_LIST_FOREACH(client->data_list, l, item) {
594 if (!strcmp(item->tag, tag)) {
602 HAPI void *client_del_data(struct client_node *client, const char *tag)
606 struct data_item *item;
608 EINA_LIST_FOREACH_SAFE(client->data_list, l, n, item) {
609 if (!strcmp(item->tag, tag)) {
611 client->data_list = eina_list_remove(client->data_list, item);
622 HAPI void client_paused(struct client_node *client)
624 if (client->paused) {
629 s_info.nr_of_paused_clients++;
632 HAPI void client_resumed(struct client_node *client)
634 if (client->paused == 0) {
639 s_info.nr_of_paused_clients--;
642 HAPI int client_init(void)
644 return LB_STATUS_SUCCESS;
647 HAPI void client_fini(void)
649 struct global_event_item *handler;
650 struct client_node *client;
654 EINA_LIST_FOREACH_SAFE(s_info.client_list, l, n, client) {
655 (void)client_destroy(client);
658 EINA_LIST_FREE(s_info.create_event_list, handler) {
662 EINA_LIST_FREE(s_info.destroy_event_list, handler) {
667 HAPI int client_global_event_handler_add(enum client_global_event event_type, int (*cb)(struct client_node *client, void *data), void *data)
669 struct global_event_item *handler;
671 handler = malloc(sizeof(*handler));
673 ErrPrint("Heap: %s\n", strerror(errno));
674 return LB_STATUS_ERROR_MEMORY;
677 handler->cbdata = data;
679 handler->deleted = 0;
681 switch (event_type) {
682 case CLIENT_GLOBAL_EVENT_CREATE:
683 s_info.create_event_list = eina_list_prepend(s_info.create_event_list, handler);
685 case CLIENT_GLOBAL_EVENT_DESTROY:
686 s_info.destroy_event_list = eina_list_prepend(s_info.destroy_event_list, handler);
690 return LB_STATUS_ERROR_INVALID;
693 return LB_STATUS_SUCCESS;
696 HAPI int client_global_event_handler_del(enum client_global_event event_type, int (*cb)(struct client_node *, void *), void *data)
700 struct global_event_item *item;
702 switch (event_type) {
703 case CLIENT_GLOBAL_EVENT_CREATE:
704 EINA_LIST_FOREACH_SAFE(s_info.create_event_list, l, n, item) {
705 if (item->cb == cb && item->cbdata == data) {
706 if (s_info.in_event_process & GLOBAL_EVENT_PROCESS_CREATE) {
709 s_info.create_event_list = eina_list_remove(s_info.create_event_list, item);
712 return LB_STATUS_SUCCESS;
716 case CLIENT_GLOBAL_EVENT_DESTROY:
717 EINA_LIST_FOREACH_SAFE(s_info.destroy_event_list, l, n, item) {
718 if (item->cb == cb && item->cbdata == data) {
719 if (s_info.in_event_process & GLOBAL_EVENT_PROCESS_DESTROY) {
722 s_info.destroy_event_list = eina_list_remove(s_info.destroy_event_list, item);
725 return LB_STATUS_SUCCESS;
733 return LB_STATUS_ERROR_NOT_EXIST;
736 HAPI int client_subscribe(struct client_node *client, const char *cluster, const char *category)
738 struct subscribe_item *item;
740 item = malloc(sizeof(*item));
742 ErrPrint("Heap: %s\n", strerror(errno));
743 return LB_STATUS_ERROR_MEMORY;
746 item->cluster = strdup(cluster);
747 if (!item->cluster) {
748 ErrPrint("Heap: %s\n", strerror(errno));
750 return LB_STATUS_ERROR_MEMORY;
753 item->category = strdup(category);
754 if (!item->category) {
755 ErrPrint("Heap: %s\n", strerror(errno));
756 DbgFree(item->cluster);
758 return LB_STATUS_ERROR_MEMORY;
761 client->subscribe_list = eina_list_append(client->subscribe_list, item);
762 return LB_STATUS_SUCCESS;
765 HAPI int client_unsubscribe(struct client_node *client, const char *cluster, const char *category)
767 struct subscribe_item *item;
771 EINA_LIST_FOREACH_SAFE(client->subscribe_list, l, n, item) {
772 if (!strcasecmp(cluster, item->cluster) && !strcasecmp(category, item->category)) {
773 client->subscribe_list = eina_list_remove(client->subscribe_list, item);
774 DbgFree(item->cluster);
775 DbgFree(item->category);
777 return LB_STATUS_SUCCESS;
781 return LB_STATUS_ERROR_NOT_EXIST;
784 HAPI int client_is_subscribed(struct client_node *client, const char *cluster, const char *category)
786 struct subscribe_item *item;
789 EINA_LIST_FOREACH(client->subscribe_list, l, item) {
790 if (!strcmp(item->cluster, "*")) {
794 if (strcasecmp(item->cluster, cluster)) {
798 if (!strcmp(item->category, "*")) {
802 if (!strcasecmp(item->category, category)) {
810 HAPI int client_browse_list(const char *cluster, const char *category, int (*cb)(struct client_node *client, void *data), void *data)
813 struct client_node *client;
816 if (!cb || !cluster || !category) {
817 return LB_STATUS_ERROR_INVALID;
821 EINA_LIST_FOREACH(s_info.client_list, l, client) {
822 if (!client_is_subscribed(client, cluster, category)) {
826 if (cb(client, data) < 0) {
827 return LB_STATUS_ERROR_CANCEL;
836 HAPI int client_nr_of_subscriber(const char *cluster, const char *category)
839 struct client_node *client;
843 EINA_LIST_FOREACH(s_info.client_list, l, client) {
844 cnt += !!client_is_subscribed(client, cluster, category);
850 HAPI int client_broadcast(struct inst_info *inst, struct packet *packet)
854 struct client_node *client;
856 list = inst ? instance_client_list(inst) : s_info.client_list;
857 EINA_LIST_FOREACH(list, l, client) {
858 if (client_pid(client) == -1) {
859 ErrPrint("Client[%p] has PID[%d]\n", client, client_pid(client));
863 (void)client_rpc_async_request(client, packet_ref(packet));
866 packet_unref(packet);
867 return LB_STATUS_SUCCESS;