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 invoke_global_destroyed_cb(client);
174 client_rpc_fini(client); /*!< Finalize the RPC after invoke destroy callbacks */
176 EINA_LIST_FREE(client->data_list, data) {
177 DbgPrint("Tag is not cleared (%s)\n", data->tag);
182 EINA_LIST_FREE(client->event_deactivate_list, event) {
186 EINA_LIST_FREE(client->subscribe_list, item) {
187 DbgFree(item->cluster);
188 DbgFree(item->category);
192 if (client->paused) {
193 s_info.nr_of_paused_clients--;
196 s_info.client_list = eina_list_remove(s_info.client_list, client);
201 * If there is any changes of clients,
202 * We should check the pause/resume states again.
204 xmonitor_handle_state_changes();
207 static inline struct client_node *create_client_data(pid_t pid)
209 struct client_node *client;
211 client = calloc(1, sizeof(*client));
213 ErrPrint("Heap: %s\n", strerror(errno));
220 s_info.client_list = eina_list_append(s_info.client_list, client);
224 * Right after create a client ADT,
225 * We assume that the client is paused.
227 client_paused(client);
228 xmonitor_handle_state_changes();
232 static Eina_Bool created_cb(void *data)
234 invoke_global_created_cb(data);
235 invoke_activated_cb(data);
238 * Client PAUSE/RESUME event must has to be sent after created event.
240 xmonitor_update_state(client_pid(data));
242 (void)client_unref(data);
243 return ECORE_CALLBACK_CANCEL;
248 * Noramlly, client ADT is created when it send the "acquire" packet.
249 * It means we have the handle for communicating with the client already,
250 * So we just create its ADT in this function.
251 * And invoke the global created event & activated event callbacks
253 HAPI struct client_node *client_create(pid_t pid, int handle)
255 struct client_node *client;
258 client = client_find_by_rpc_handle(handle);
260 ErrPrint("Client %d(%d) is already exists\n", pid, handle);
264 client = create_client_data(pid);
266 ErrPrint("Failed to create a new client (%d)\n", pid);
270 ret = client_rpc_init(client, handle);
272 client = client_unref(client);
273 ErrPrint("Failed to initialize the RPC for %d, Destroy client data %p(has to be 0x0)\n", pid, client);
277 * To save the time to send reply packet to the client.
279 if (ecore_timer_add(DELAY_TIME, created_cb, client_ref(client)) == NULL) {
280 ErrPrint("Failed to add a timer for client created event\n");
281 client = client_unref(client); /* Decrease refcnt for argument */
282 client = client_unref(client); /* Destroy client object */
290 HAPI struct client_node *client_ref(struct client_node *client)
300 HAPI struct client_node *client_unref(struct client_node *client)
306 if (client->refcnt == 0) {
307 ErrPrint("Client refcnt is not managed correctly\n");
312 if (client->refcnt == 0) {
313 destroy_client_data(client);
320 HAPI const int const client_refcnt(const struct client_node *client)
322 return client->refcnt;
325 HAPI const pid_t const client_pid(const struct client_node *client)
327 return client ? client->pid : (pid_t)-1;
330 HAPI struct client_node *client_find_by_pid(pid_t pid)
333 struct client_node *client;
335 EINA_LIST_FOREACH(s_info.client_list, l, client) {
336 if (client->pid == pid) {
344 HAPI struct client_node *client_find_by_rpc_handle(int handle)
347 struct client_node *client;
350 ErrPrint("Invalid handle %d\n", handle);
354 EINA_LIST_FOREACH(s_info.client_list, l, client) {
355 if (client_rpc_handle(client) == handle) {
363 HAPI const int const client_count_paused(void)
365 return s_info.nr_of_paused_clients;
368 HAPI int client_is_all_paused(void)
370 DbgPrint("%d, %d\n", eina_list_count(s_info.client_list), s_info.nr_of_paused_clients);
371 return eina_list_count(s_info.client_list) == s_info.nr_of_paused_clients;
374 HAPI int client_count(void)
376 return eina_list_count(s_info.client_list);
379 HAPI struct client_node *client_deactivated_by_fault(struct client_node *client)
381 if (!client || client->faulted) {
385 ErrPrint("Client[%p] is faulted(%d), pid(%d)\n", client, client->refcnt, client->pid);
387 client->pid = (pid_t)-1;
389 invoke_deactivated_cb(client);
390 client = client_destroy(client);
393 * Who invokes this function has to care the reference counter of a client
394 * do I need to invoke the deactivated callback from here?
395 * client->pid = (pid_t)-1;
396 * slave_unref(client)
401 HAPI const int const client_is_faulted(const struct client_node *client)
405 * If the "client" is NIL, I assume that it is fault so returns TRUE(1)
407 return client ? client->faulted : 1;
410 HAPI void client_reset_fault(struct client_node *client)
417 HAPI int client_event_callback_add(struct client_node *client, enum client_event event, int (*cb)(struct client_node *, void *), void *data)
419 struct event_item *item;
422 ErrPrint("Invalid callback (cb == NULL)\n");
423 return LB_STATUS_ERROR_INVALID;
426 item = calloc(1, sizeof(*item));
428 ErrPrint("Heap: %s\n", strerror(errno));
429 return LB_STATUS_ERROR_MEMORY;
437 * Use the eina_list_prepend API.
438 * To keep the sequence of a callback invocation.
440 * Here is an example sequence.
442 * client_event_callback_add(CALLBACK_01);
443 * client_event_callback_add(CALLBACK_02);
444 * client_event_callback_add(CALLBACK_03);
446 * Then the invoke_event_callback function will call the CALLBACKS as below sequence
454 case CLIENT_EVENT_DEACTIVATE:
455 client->event_deactivate_list = eina_list_prepend(client->event_deactivate_list, item);
457 case CLIENT_EVENT_ACTIVATE:
458 client->event_activate_list = eina_list_prepend(client->event_activate_list, item);
462 return LB_STATUS_ERROR_INVALID;
465 return LB_STATUS_SUCCESS;
468 HAPI int client_event_callback_del(struct client_node *client, enum client_event event, int (*cb)(struct client_node *, void *), void *data)
470 struct event_item *item;
475 ErrPrint("Invalid callback (cb == NULL)\n");
476 return LB_STATUS_ERROR_INVALID;
480 case CLIENT_EVENT_DEACTIVATE:
481 EINA_LIST_FOREACH_SAFE(client->event_deactivate_list, l, n, item) {
482 if (item->cb == cb && item->data == data) {
483 client->event_deactivate_list = eina_list_remove(client->event_deactivate_list, item);
485 return LB_STATUS_SUCCESS;
490 case CLIENT_EVENT_ACTIVATE:
491 EINA_LIST_FOREACH_SAFE(client->event_activate_list, l, n, item) {
492 if (item->cb == cb && item->data == data) {
493 client->event_activate_list = eina_list_remove(client->event_activate_list, item);
495 return LB_STATUS_SUCCESS;
501 ErrPrint("Invalid event\n");
505 return LB_STATUS_ERROR_NOT_EXIST;
508 HAPI int client_set_data(struct client_node *client, const char *tag, void *data)
510 struct data_item *item;
512 item = calloc(1, sizeof(*item));
514 ErrPrint("Heap: %s\n", strerror(errno));
515 return LB_STATUS_ERROR_MEMORY;
518 item->tag = strdup(tag);
520 ErrPrint("Heap: %s\n", strerror(errno));
522 return LB_STATUS_ERROR_MEMORY;
527 client->data_list = eina_list_append(client->data_list, item);
528 return LB_STATUS_SUCCESS;
531 HAPI void *client_data(struct client_node *client, const char *tag)
534 struct data_item *item;
536 EINA_LIST_FOREACH(client->data_list, l, item) {
537 if (!strcmp(item->tag, tag)) {
545 HAPI void *client_del_data(struct client_node *client, const char *tag)
549 struct data_item *item;
551 EINA_LIST_FOREACH_SAFE(client->data_list, l, n, item) {
552 if (!strcmp(item->tag, tag)) {
554 client->data_list = eina_list_remove(client->data_list, item);
565 HAPI void client_paused(struct client_node *client)
567 if (client->paused) {
572 s_info.nr_of_paused_clients++;
575 HAPI void client_resumed(struct client_node *client)
577 if (client->paused == 0) {
582 s_info.nr_of_paused_clients--;
585 HAPI int client_init(void)
587 return LB_STATUS_SUCCESS;
590 HAPI void client_fini(void)
592 struct global_event_handler *handler;
593 struct client_node *client;
597 EINA_LIST_FOREACH_SAFE(s_info.client_list, l, n, client) {
598 (void)client_destroy(client);
601 EINA_LIST_FREE(s_info.create_event_list, handler) {
605 EINA_LIST_FREE(s_info.destroy_event_list, handler) {
610 HAPI int client_global_event_handler_add(enum client_global_event event_type, int (*cb)(struct client_node *client, void *data), void *data)
612 struct global_event_handler *handler;
614 handler = malloc(sizeof(*handler));
616 ErrPrint("Heap: %s\n", strerror(errno));
617 return LB_STATUS_ERROR_MEMORY;
620 handler->cbdata = data;
623 switch (event_type) {
624 case CLIENT_GLOBAL_EVENT_CREATE:
625 s_info.create_event_list = eina_list_prepend(s_info.create_event_list, handler);
627 case CLIENT_GLOBAL_EVENT_DESTROY:
628 s_info.destroy_event_list = eina_list_prepend(s_info.destroy_event_list, handler);
632 return LB_STATUS_ERROR_INVALID;
635 return LB_STATUS_SUCCESS;
638 HAPI int client_global_event_handler_del(enum client_global_event event_type, int (*cb)(struct client_node *, void *), void *data)
642 struct global_event_handler *handler;
644 switch (event_type) {
645 case CLIENT_GLOBAL_EVENT_CREATE:
646 EINA_LIST_FOREACH_SAFE(s_info.create_event_list, l, n, handler) {
647 if (handler->cb == cb && handler->cbdata == data) {
648 s_info.create_event_list = eina_list_remove(s_info.create_event_list, handler);
650 return LB_STATUS_SUCCESS;
654 case CLIENT_GLOBAL_EVENT_DESTROY:
655 EINA_LIST_FOREACH_SAFE(s_info.destroy_event_list, l, n, handler) {
656 if (handler->cb == cb && handler->cbdata == data) {
657 s_info.destroy_event_list = eina_list_remove(s_info.destroy_event_list, handler);
659 return LB_STATUS_SUCCESS;
667 return LB_STATUS_ERROR_NOT_EXIST;
670 HAPI int client_subscribe(struct client_node *client, const char *cluster, const char *category)
672 struct subscribe_item *item;
674 item = malloc(sizeof(*item));
676 ErrPrint("Heap: %s\n", strerror(errno));
677 return LB_STATUS_ERROR_MEMORY;
680 item->cluster = strdup(cluster);
681 if (!item->cluster) {
682 ErrPrint("Heap: %s\n", strerror(errno));
684 return LB_STATUS_ERROR_MEMORY;
687 item->category = strdup(category);
688 if (!item->category) {
689 ErrPrint("Heap: %s\n", strerror(errno));
690 DbgFree(item->cluster);
692 return LB_STATUS_ERROR_MEMORY;
695 client->subscribe_list = eina_list_append(client->subscribe_list, item);
696 return LB_STATUS_SUCCESS;
699 HAPI int client_unsubscribe(struct client_node *client, const char *cluster, const char *category)
701 struct subscribe_item *item;
705 EINA_LIST_FOREACH_SAFE(client->subscribe_list, l, n, item) {
706 if (!strcasecmp(cluster, item->cluster) && !strcasecmp(category, item->category)) {
707 client->subscribe_list = eina_list_remove(client->subscribe_list, item);
708 DbgFree(item->cluster);
709 DbgFree(item->category);
711 return LB_STATUS_SUCCESS;
715 return LB_STATUS_ERROR_NOT_EXIST;
718 HAPI int client_is_subscribed(struct client_node *client, const char *cluster, const char *category)
720 struct subscribe_item *item;
723 EINA_LIST_FOREACH(client->subscribe_list, l, item) {
724 if (!strcmp(item->cluster, "*")) {
728 if (strcasecmp(item->cluster, cluster)) {
732 if (!strcmp(item->category, "*")) {
736 if (!strcasecmp(item->category, category)) {
744 HAPI int client_browse_list(const char *cluster, const char *category, int (*cb)(struct client_node *client, void *data), void *data)
747 struct client_node *client;
750 if (!cb || !cluster || !category) {
751 return LB_STATUS_ERROR_INVALID;
755 EINA_LIST_FOREACH(s_info.client_list, l, client) {
756 if (!client_is_subscribed(client, cluster, category)) {
760 if (cb(client, data) < 0) {
761 return LB_STATUS_ERROR_CANCEL;
770 HAPI int client_nr_of_subscriber(const char *cluster, const char *category)
773 struct client_node *client;
777 EINA_LIST_FOREACH(s_info.client_list, l, client) {
778 cnt += !!client_is_subscribed(client, cluster, category);
784 HAPI int client_broadcast(struct inst_info *inst, struct packet *packet)
788 struct client_node *client;
790 list = inst ? instance_client_list(inst) : s_info.client_list;
791 EINA_LIST_FOREACH(list, l, client) {
792 if (client_pid(client) == -1) {
793 ErrPrint("Client[%p] has PID[%d]\n", client, client_pid(client));
797 (void)client_rpc_async_request(client, packet_ref(packet));
800 packet_unref(packet);
801 return LB_STATUS_SUCCESS;