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 Eina_List *create_event_list;
43 Eina_List *destroy_event_list;
46 .nr_of_paused_clients = 0,
47 .create_event_list = NULL,
48 .destroy_event_list = NULL,
51 struct subscribe_item {
56 struct global_event_handler {
58 int (*cb)(struct client_node *client, void *data);
68 int (*cb)(struct client_node *, void *);
77 Eina_List *event_deactivate_list;
78 Eina_List *event_activate_list;
80 Eina_List *subscribe_list;
85 static inline void invoke_global_destroyed_cb(struct client_node *client)
89 struct global_event_handler *item;
91 EINA_LIST_FOREACH_SAFE(s_info.destroy_event_list, l, n, item) {
93 ErrPrint("Callback function is not valid\n");
97 if (item->cb(client, item->cbdata) < 0) {
98 if (eina_list_data_find(s_info.destroy_event_list, item)) {
99 s_info.destroy_event_list = eina_list_remove(s_info.destroy_event_list, item);
106 static inline void invoke_global_created_cb(struct client_node *client)
110 struct global_event_handler *item;
112 EINA_LIST_FOREACH_SAFE(s_info.create_event_list, l, n, item) {
114 ErrPrint("Callback function is not valid\n");
118 if (item->cb(client, item->cbdata) < 0) {
119 if (eina_list_data_find(s_info.create_event_list, item)) {
120 s_info.create_event_list = eina_list_remove(s_info.create_event_list, item);
127 static inline void invoke_deactivated_cb(struct client_node *client)
129 struct event_item *item;
134 client_ref(client); /*!< Prevent from client deletion in the callbacks */
135 EINA_LIST_FOREACH_SAFE(client->event_deactivate_list, l, n, item) {
136 ret = item->cb(client, item->data);
138 if (eina_list_data_find(client->event_deactivate_list, item)) {
139 client->event_deactivate_list = eina_list_remove(client->event_deactivate_list, item);
144 client_unref(client);
147 static inline void invoke_activated_cb(struct client_node *client)
149 struct event_item *item;
154 client_ref(client); /*!< Prevent from client deletion in the callbacks */
155 EINA_LIST_FOREACH_SAFE(client->event_activate_list, l, n, item) {
156 ret = item->cb(client, item->data);
158 if (eina_list_data_find(client->event_activate_list, item)) {
159 client->event_activate_list = eina_list_remove(client->event_activate_list, item);
164 client_unref(client);
167 static inline void destroy_client_data(struct client_node *client)
169 struct event_item *event;
170 struct data_item *data;
171 struct subscribe_item *item;
173 DbgPrint("Client %p is destroyed\n", client);
175 invoke_global_destroyed_cb(client);
176 client_rpc_fini(client); /*!< Finalize the RPC after invoke destroy callbacks */
178 EINA_LIST_FREE(client->data_list, data) {
179 DbgPrint("Tag is not cleared (%s)\n", data->tag);
184 EINA_LIST_FREE(client->event_deactivate_list, event) {
188 EINA_LIST_FREE(client->subscribe_list, item) {
189 DbgFree(item->cluster);
190 DbgFree(item->category);
195 s_info.nr_of_paused_clients--;
197 s_info.client_list = eina_list_remove(s_info.client_list, client);
202 * If there is any changes of clients,
203 * We should check the pause/resume states again.
205 xmonitor_handle_state_changes();
208 static inline struct client_node *create_client_data(pid_t pid)
210 struct client_node *client;
212 client = calloc(1, sizeof(*client));
214 ErrPrint("Heap: %s\n", strerror(errno));
221 s_info.client_list = eina_list_append(s_info.client_list, client);
225 * Right after create a client ADT,
226 * We assume that the client is paused.
228 client_paused(client);
229 xmonitor_handle_state_changes();
233 static Eina_Bool created_cb(void *data)
235 invoke_global_created_cb(data);
236 invoke_activated_cb(data);
239 * Client PAUSE/RESUME event must has to be sent after created event.
241 xmonitor_update_state(client_pid(data));
242 return ECORE_CALLBACK_CANCEL;
247 * Noramlly, client ADT is created when it send the "acquire" packet.
248 * It means we have the handle for communicating with the client already,
249 * So we just create its ADT in this function.
250 * And invoke the global created event & activated event callbacks
252 HAPI struct client_node *client_create(pid_t pid, int handle)
254 struct client_node *client;
257 client = client_find_by_pid(pid);
259 ErrPrint("Client %d is already exists\n", pid);
263 client = create_client_data(pid);
265 ErrPrint("Failed to create a new client (%d)\n", pid);
269 ret = client_rpc_init(client, handle);
271 client = client_unref(client);
272 ErrPrint("Failed to initialize the RPC for %d, Destroy client data %p(has to be 0x0)\n", pid, client);
276 * To save the time to send reply packet to the client.
278 if (ecore_timer_add(DELAY_TIME, created_cb, client) == NULL) {
279 ErrPrint("Failed to add a timer for client created event\n");
280 client = client_unref(client);
288 HAPI struct client_node *client_ref(struct client_node *client)
297 HAPI struct client_node *client_unref(struct client_node *client)
302 if (client->refcnt == 0) {
303 ErrPrint("Client refcnt is not managed correctly\n");
308 if (client->refcnt == 0) {
309 destroy_client_data(client);
316 HAPI const int const client_refcnt(const struct client_node *client)
318 return client->refcnt;
321 HAPI const pid_t const client_pid(const struct client_node *client)
323 return client ? client->pid : (pid_t)-1;
326 HAPI struct client_node *client_find_by_pid(pid_t pid)
329 struct client_node *client;
331 EINA_LIST_FOREACH(s_info.client_list, l, client) {
332 if (client->pid == pid)
339 HAPI struct client_node *client_find_by_rpc_handle(int handle)
342 struct client_node *client;
345 ErrPrint("Invalid handle %d\n", handle);
349 EINA_LIST_FOREACH(s_info.client_list, l, client) {
350 if (client_rpc_handle(client) == handle)
357 HAPI const int const client_count_paused(void)
359 return s_info.nr_of_paused_clients;
362 HAPI int client_is_all_paused(void)
364 DbgPrint("%d, %d\n", eina_list_count(s_info.client_list), s_info.nr_of_paused_clients);
365 return eina_list_count(s_info.client_list) == s_info.nr_of_paused_clients;
368 HAPI int client_count(void)
370 return eina_list_count(s_info.client_list);
373 HAPI struct client_node *client_deactivated_by_fault(struct client_node *client)
375 if (!client || client->faulted)
378 ErrPrint("Client[%p] is faulted(%d), pid(%d)\n", client, client->refcnt, client->pid);
380 client->pid = (pid_t)-1;
382 invoke_deactivated_cb(client);
383 client = client_destroy(client);
386 * Who invokes this function has to care the reference counter of a client
387 * do I need to invoke the deactivated callback from here?
388 * client->pid = (pid_t)-1;
389 * slave_unref(client)
394 HAPI const int const client_is_faulted(const struct client_node *client)
398 * If the "client" is NIL, I assume that it is fault so returns TRUE(1)
400 return client ? client->faulted : 1;
403 HAPI void client_reset_fault(struct client_node *client)
409 HAPI int client_event_callback_add(struct client_node *client, enum client_event event, int (*cb)(struct client_node *, void *), void *data)
411 struct event_item *item;
414 ErrPrint("Invalid callback (cb == NULL)\n");
415 return LB_STATUS_ERROR_INVALID;
418 item = calloc(1, sizeof(*item));
420 ErrPrint("Heap: %s\n", strerror(errno));
421 return LB_STATUS_ERROR_MEMORY;
429 * Use the eina_list_prepend API.
430 * To keep the sequence of a callback invocation.
432 * Here is an example sequence.
434 * client_event_callback_add(CALLBACK_01);
435 * client_event_callback_add(CALLBACK_02);
436 * client_event_callback_add(CALLBACK_03);
438 * Then the invoke_event_callback function will call the CALLBACKS as below sequence
446 case CLIENT_EVENT_DEACTIVATE:
447 client->event_deactivate_list = eina_list_prepend(client->event_deactivate_list, item);
449 case CLIENT_EVENT_ACTIVATE:
450 client->event_activate_list = eina_list_prepend(client->event_activate_list, item);
454 return LB_STATUS_ERROR_INVALID;
457 return LB_STATUS_SUCCESS;
460 HAPI int client_event_callback_del(struct client_node *client, enum client_event event, int (*cb)(struct client_node *, void *), void *data)
462 struct event_item *item;
467 ErrPrint("Invalid callback (cb == NULL)\n");
468 return LB_STATUS_ERROR_INVALID;
472 case CLIENT_EVENT_DEACTIVATE:
473 EINA_LIST_FOREACH_SAFE(client->event_deactivate_list, l, n, item) {
474 if (item->cb == cb && item->data == data) {
475 client->event_deactivate_list = eina_list_remove(client->event_deactivate_list, item);
477 return LB_STATUS_SUCCESS;
482 case CLIENT_EVENT_ACTIVATE:
483 EINA_LIST_FOREACH_SAFE(client->event_activate_list, l, n, item) {
484 if (item->cb == cb && item->data == data) {
485 client->event_activate_list = eina_list_remove(client->event_activate_list, item);
487 return LB_STATUS_SUCCESS;
493 ErrPrint("Invalid event\n");
497 return LB_STATUS_ERROR_NOT_EXIST;
500 HAPI int client_set_data(struct client_node *client, const char *tag, void *data)
502 struct data_item *item;
504 item = calloc(1, sizeof(*item));
506 ErrPrint("Heap: %s\n", strerror(errno));
507 return LB_STATUS_ERROR_MEMORY;
510 item->tag = strdup(tag);
512 ErrPrint("Heap: %s\n", strerror(errno));
514 return LB_STATUS_ERROR_MEMORY;
519 client->data_list = eina_list_append(client->data_list, item);
520 return LB_STATUS_SUCCESS;
523 HAPI void *client_data(struct client_node *client, const char *tag)
526 struct data_item *item;
528 EINA_LIST_FOREACH(client->data_list, l, item) {
529 if (!strcmp(item->tag, tag))
536 HAPI void *client_del_data(struct client_node *client, const char *tag)
540 struct data_item *item;
542 EINA_LIST_FOREACH_SAFE(client->data_list, l, n, item) {
543 if (!strcmp(item->tag, tag)) {
545 client->data_list = eina_list_remove(client->data_list, item);
556 HAPI void client_paused(struct client_node *client)
562 s_info.nr_of_paused_clients++;
565 HAPI void client_resumed(struct client_node *client)
567 if (client->paused == 0)
571 s_info.nr_of_paused_clients--;
574 HAPI int client_init(void)
576 return LB_STATUS_SUCCESS;
579 HAPI void client_fini(void)
581 struct global_event_handler *handler;
582 struct client_node *client;
586 EINA_LIST_FOREACH_SAFE(s_info.client_list, l, n, client) {
587 (void)client_destroy(client);
590 EINA_LIST_FREE(s_info.create_event_list, handler) {
594 EINA_LIST_FREE(s_info.destroy_event_list, handler) {
599 HAPI const int const client_is_activated(const struct client_node *client)
601 return client ? (client->pid != (pid_t)-1) : 1;
604 HAPI int client_global_event_handler_add(enum client_global_event event_type, int (*cb)(struct client_node *client, void *data), void *data)
606 struct global_event_handler *handler;
608 handler = malloc(sizeof(*handler));
610 ErrPrint("Heap: %s\n", strerror(errno));
611 return LB_STATUS_ERROR_MEMORY;
614 handler->cbdata = data;
617 switch (event_type) {
618 case CLIENT_GLOBAL_EVENT_CREATE:
619 s_info.create_event_list = eina_list_prepend(s_info.create_event_list, handler);
621 case CLIENT_GLOBAL_EVENT_DESTROY:
622 s_info.destroy_event_list = eina_list_prepend(s_info.destroy_event_list, handler);
626 return LB_STATUS_ERROR_INVALID;
629 return LB_STATUS_SUCCESS;
632 HAPI int client_global_event_handler_del(enum client_global_event event_type, int (*cb)(struct client_node *, void *), void *data)
636 struct global_event_handler *handler;
638 switch (event_type) {
639 case CLIENT_GLOBAL_EVENT_CREATE:
640 EINA_LIST_FOREACH_SAFE(s_info.create_event_list, l, n, handler) {
641 if (handler->cb == cb && handler->cbdata == data) {
642 s_info.create_event_list = eina_list_remove(s_info.create_event_list, handler);
644 return LB_STATUS_SUCCESS;
648 case CLIENT_GLOBAL_EVENT_DESTROY:
649 EINA_LIST_FOREACH_SAFE(s_info.destroy_event_list, l, n, handler) {
650 if (handler->cb == cb && handler->cbdata == data) {
651 s_info.destroy_event_list = eina_list_remove(s_info.destroy_event_list, handler);
653 return LB_STATUS_SUCCESS;
661 return LB_STATUS_ERROR_NOT_EXIST;
664 HAPI int client_subscribe(struct client_node *client, const char *cluster, const char *category)
666 struct subscribe_item *item;
668 item = malloc(sizeof(*item));
670 ErrPrint("Heap: %s\n", strerror(errno));
671 return LB_STATUS_ERROR_MEMORY;
674 item->cluster = strdup(cluster);
675 if (!item->cluster) {
676 ErrPrint("Heap: %s\n", strerror(errno));
678 return LB_STATUS_ERROR_MEMORY;
681 item->category = strdup(category);
682 if (!item->category) {
683 ErrPrint("Heap: %s\n", strerror(errno));
684 DbgFree(item->cluster);
686 return LB_STATUS_ERROR_MEMORY;
689 client->subscribe_list = eina_list_append(client->subscribe_list, item);
690 return LB_STATUS_SUCCESS;
693 HAPI int client_unsubscribe(struct client_node *client, const char *cluster, const char *category)
695 struct subscribe_item *item;
699 EINA_LIST_FOREACH_SAFE(client->subscribe_list, l, n, item) {
700 if (!strcasecmp(cluster, item->cluster) && !strcasecmp(category, item->category)) {
701 client->subscribe_list = eina_list_remove(client->subscribe_list, item);
702 DbgFree(item->cluster);
703 DbgFree(item->category);
705 return LB_STATUS_SUCCESS;
709 return LB_STATUS_ERROR_NOT_EXIST;
712 HAPI int client_is_subscribed(struct client_node *client, const char *cluster, const char *category)
714 struct subscribe_item *item;
717 EINA_LIST_FOREACH(client->subscribe_list, l, item) {
718 if (!strcmp(item->cluster, "*"))
721 if (strcasecmp(item->cluster, cluster))
724 if (!strcmp(item->category, "*"))
727 if (!strcasecmp(item->category, category))
734 HAPI int client_browse_list(const char *cluster, const char *category, int (*cb)(struct client_node *client, void *data), void *data)
737 struct client_node *client;
740 if (!cb || !cluster || !category)
741 return LB_STATUS_ERROR_INVALID;
744 EINA_LIST_FOREACH(s_info.client_list, l, client) {
745 if (!client_is_subscribed(client, cluster, category))
748 if (cb(client, data) < 0)
749 return LB_STATUS_ERROR_CANCEL;
757 HAPI int client_nr_of_subscriber(const char *cluster, const char *category)
760 struct client_node *client;
764 EINA_LIST_FOREACH(s_info.client_list, l, client) {
765 cnt += !!client_is_subscribed(client, cluster, category);
771 HAPI int client_broadcast(struct inst_info *inst, struct packet *packet)
775 struct client_node *client;
777 list = inst ? instance_client_list(inst) : s_info.client_list;
778 EINA_LIST_FOREACH(list, l, client) {
779 if (client_pid(client) < 0) {
780 ErrPrint("Client[%p] has PID[%d]\n", client, client_pid(client));
784 (void)client_rpc_async_request(client, packet_ref(packet));
787 packet_unref(packet);
788 return LB_STATUS_SUCCESS;