diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/badge_service.c | 4 | ||||
-rw-r--r-- | src/instance.c | 93 | ||||
-rw-r--r-- | src/main.c | 7 | ||||
-rw-r--r-- | src/notification_service.c | 4 | ||||
-rw-r--r-- | src/server.c | 12 | ||||
-rw-r--r-- | src/service_common.c | 178 | ||||
-rw-r--r-- | src/setting.c | 73 | ||||
-rw-r--r-- | src/shortcut_service.c | 4 | ||||
-rw-r--r-- | src/util.c | 2 | ||||
-rw-r--r-- | src/utility_service.c | 298 |
10 files changed, 661 insertions, 14 deletions
diff --git a/src/badge_service.c b/src/badge_service.c index db3e090..9b39e94 100644 --- a/src/badge_service.c +++ b/src/badge_service.c @@ -269,6 +269,10 @@ static int service_thread_main(struct tcb *tcb, struct packet *packet, void *dat }; DbgPrint("TCB: %p, Packet: %p\n", tcb, packet); + if (!packet) { + DbgPrint("TCB: %p is terminated\n", tcb); + return 0; + } command = packet_command(packet); if (!command) { diff --git a/src/instance.c b/src/instance.c index 32d18cc..1005fdc 100644 --- a/src/instance.c +++ b/src/instance.c @@ -83,6 +83,11 @@ struct event_item { void *data; }; +struct tag_item { + char *tag; + void *data; +}; + struct inst_info { struct pkg_info *info; @@ -144,6 +149,8 @@ struct inst_info { Ecore_Timer *update_timer; /*!< Only used for secured livebox */ Eina_List *delete_event_list; + + Eina_List *data_list; }; #define CLIENT_SEND_EVENT(instance, packet) ((instance)->client ? client_rpc_async_request((instance)->client, (packet)) : client_broadcast((instance), (packet))) @@ -595,6 +602,7 @@ static inline void destroy_instance(struct inst_info *inst) enum pd_type pd_type; struct slave_node *slave; struct event_item *item; + struct tag_item *tag_item; invoke_delete_callbacks(inst); @@ -633,6 +641,12 @@ static inline void destroy_instance(struct inst_info *inst) if (inst->update_timer) ecore_timer_del(inst->update_timer); + EINA_LIST_FREE(inst->data_list, tag_item) { + DbgPrint("Tagged item[%s] %p\n", tag_item->tag, tag_item->data); + free(tag_item->tag); + free(tag_item); + } + /*! * \note * @@ -1301,6 +1315,9 @@ static int pd_buffer_close_cb(struct client_node *client, void *inst) ret = instance_slave_close_pd(inst, client); DbgPrint("Forcely close the PD ret: %d\n", ret); + + instance_unref(inst); + return -1; /* Delete this callback */ } @@ -1315,6 +1332,8 @@ static int pd_script_close_cb(struct client_node *client, void *inst) ret = instance_slave_close_pd(inst, client); DbgPrint("Forcely close the PD ret: %d\n", ret); + instance_unref(inst); + return -1; /* Delete this callback */ } @@ -3038,4 +3057,78 @@ HAPI void instance_fini(void) { } +static inline struct tag_item *find_tag_item(struct inst_info *inst, const char *tag) +{ + struct tag_item *item; + Eina_List *l; + + EINA_LIST_FOREACH(inst->data_list, l, item) { + if (!strcmp(item->tag, tag)) + return item; + } + + return NULL; +} + +HAPI int instance_set_data(struct inst_info *inst, const char *tag, void *data) +{ + struct tag_item *item; + + item = find_tag_item(inst, tag); + if (!item) { + item = malloc(sizeof(*item)); + if (!item) { + ErrPrint("Heap: %s\n", strerror(errno)); + return LB_STATUS_ERROR_MEMORY; + } + + item->tag = strdup(tag); + if (!item->tag) { + ErrPrint("Heap: %s\n", strerror(errno)); + free(item); + return LB_STATUS_ERROR_MEMORY; + } + + inst->data_list = eina_list_append(inst->data_list, item); + } + + if (!data) { + inst->data_list = eina_list_remove(inst->data_list, item); + free(item->tag); + free(item); + } else { + item->data = data; + } + + return LB_STATUS_SUCCESS; +} + +HAPI void *instance_del_data(struct inst_info *inst, const char *tag) +{ + struct tag_item *item; + void *data; + + item = find_tag_item(inst, tag); + if (!item) + return NULL; + + inst->data_list = eina_list_remove(inst->data_list, item); + data = item->data; + free(item->tag); + free(item); + + return data; +} + +HAPI void *instance_get_data(struct inst_info *inst, const char *tag) +{ + struct tag_item *item; + + item = find_tag_item(inst, tag); + if (!item) + return NULL; + + return item->data; +} + /* End of a file */ @@ -53,6 +53,7 @@ #include "event.h" #include "shortcut_service.h" #include "notification_service.h" +#include "utility_service.h" #include "badge_service.h" #if defined(FLOG) @@ -156,11 +157,11 @@ static inline int app_terminate(void) static void signal_handler(int signum, siginfo_t *info, void *unused) { int fd; + CRITICAL_LOG("Terminated(SIGTERM)\n"); fd = creat("/tmp/.stop.provider", 0644); if (fd > 0) close(fd); - exit(0); } int main(int argc, char *argv[]) @@ -174,7 +175,7 @@ int main(int argc, char *argv[]) */ ret = critical_log_init(util_basename(argv[0])); if (ret < 0) - fprintf(stderr, "Failed to init the critical log\n"); + ErrPrint("Failed to init the critical log\n"); #if defined(FLOG) __file_log_fp = fopen("/tmp/live.log", "w+t"); @@ -245,6 +246,7 @@ int main(int argc, char *argv[]) shortcut_service_init(); notification_service_init(); badge_service_init(); + utility_service_init(); script_init(); app_create(); @@ -256,6 +258,7 @@ int main(int argc, char *argv[]) app_terminate(); script_fini(); + utility_service_fini(); badge_service_fini(); notification_service_fini(); shortcut_service_fini(); diff --git a/src/notification_service.c b/src/notification_service.c index 2c2bcea..40f3b91 100644 --- a/src/notification_service.c +++ b/src/notification_service.c @@ -329,6 +329,10 @@ static int service_thread_main(struct tcb *tcb, struct packet *packet, void *dat }; DbgPrint("TCB: %p, Packet: %p\n", tcb, packet); + if (!packet) { + DbgPrint("TCB: %p is terminated\n", tcb); + return 0; + } command = packet_command(packet); if (!command) { diff --git a/src/server.c b/src/server.c index fea14c9..d7ab848 100644 --- a/src/server.c +++ b/src/server.c @@ -5645,6 +5645,10 @@ out: static Eina_Bool lazy_pd_created_cb(void *data) { + /*! + * After unref instance first, + * if the instance is not destroyed, try to notify the created PD event to the client. + */ if (instance_unref(data)) { int ret; ret = instance_client_pd_created(data, LB_STATUS_SUCCESS); @@ -5807,6 +5811,14 @@ static struct packet *client_create_pd(pid_t pid, int handle, const struct packe * the event correctly. */ inst = instance_ref(inst); /* To guarantee the inst */ + + /*! + * \note + * At here, we don't need to rememeber the timer object. + * Even if the timer callback is called, after the instance is destroyed. + * lazy_pd_created_cb will decrease the instance refcnt first. + * At that time, if the instance is released, the timer callback will do nothing. + */ if (!ecore_timer_add(DELAY_TIME, lazy_pd_created_cb, inst)) { instance_unref(inst); script_handler_unload(instance_pd_script(inst), 1); diff --git a/src/service_common.c b/src/service_common.c index 6a32976..0190bf6 100644 --- a/src/service_common.c +++ b/src/service_common.c @@ -21,6 +21,7 @@ #include <errno.h> #include <sys/time.h> #include <sys/types.h> +#include <sys/timerfd.h> #include <unistd.h> #include <fcntl.h> @@ -37,11 +38,25 @@ int errno; +struct service_event_item { + enum { + SERVICE_EVENT_TIMER, + } type; + + union { + struct { + int fd; + } timer; + } info; + + int (*event_cb)(struct service_context *svc_cx, void *data); + void *cbdata; +}; + /*! * \note * Server information and global (only in this file-scope) variables are defined */ - struct service_context { pthread_t server_thid; /*!< Server thread Id */ int fd; /*!< Server socket handle */ @@ -55,6 +70,8 @@ struct service_context { int (*service_thread_main)(struct tcb *tcb, struct packet *packet, void *data); void *service_thread_data; + + Eina_List *event_list; }; struct packet_info { @@ -380,6 +397,88 @@ static inline void tcb_destroy(struct service_context *svc_ctx, struct tcb *tcb) } /*! + * \note + * SERVER THREAD + */ +static inline int find_max_fd(struct service_context *svc_ctx) +{ + int fd; + Eina_List *l; + struct service_event_item *item; + + fd = svc_ctx->fd > svc_ctx->tcb_pipe[PIPE_READ] ? svc_ctx->fd : svc_ctx->tcb_pipe[PIPE_READ]; + fd = fd > svc_ctx->evt_pipe[PIPE_READ] ? fd : svc_ctx->evt_pipe[PIPE_READ]; + + EINA_LIST_FOREACH(svc_ctx->event_list, l, item) { + if (item->type == SERVICE_EVENT_TIMER && fd < item->info.timer.fd) + fd = item->info.timer.fd; + } + + fd += 1; + return fd; +} + +/*! + * \note + * SERVER THREAD + */ +static inline void update_fdset(struct service_context *svc_ctx, fd_set *set) +{ + Eina_List *l; + struct service_event_item *item; + + FD_ZERO(set); + FD_SET(svc_ctx->fd, set); + FD_SET(svc_ctx->tcb_pipe[PIPE_READ], set); + FD_SET(svc_ctx->evt_pipe[PIPE_READ], set); + + EINA_LIST_FOREACH(svc_ctx->event_list, l, item) { + if (item->type == SERVICE_EVENT_TIMER) + FD_SET(item->info.timer.fd, set); + } +} + +/*! + * \note + * SERVER THREAD + */ +static inline void processing_timer_event(struct service_context *svc_ctx, fd_set *set) +{ + uint64_t expired_count; + Eina_List *l; + Eina_List *n; + struct service_event_item *item; + + EINA_LIST_FOREACH_SAFE(svc_ctx->event_list, l, n, item) { + switch (item->type) { + case SERVICE_EVENT_TIMER: + if (!FD_ISSET(item->info.timer.fd, set)) + break; + + if (read(item->info.timer.fd, &expired_count, sizeof(expired_count)) == sizeof(expired_count)) { + DbgPrint("Expired %d times\n", expired_count); + if (item->event_cb(svc_ctx, item->cbdata) >= 0) + break; + } else { + ErrPrint("read: %s\n", strerror(errno)); + } + + if (!eina_list_data_find(svc_ctx->event_list, item)) + break; + + svc_ctx->event_list = eina_list_remove(svc_ctx->event_list, item); + if (close(item->info.timer.fd) < 0) + ErrPrint("close: %s\n", strerror(errno)); + free(item); + break; + default: + ErrPrint("Unknown event: %d\n", item->type); + break; + } + } +} + +/*! * Accept new client connections * And create a new thread for service. * @@ -398,15 +497,9 @@ static void *server_main(void *data) struct packet_info *packet_info; DbgPrint("Server thread is activated\n"); - fd = svc_ctx->fd > svc_ctx->tcb_pipe[PIPE_READ] ? svc_ctx->fd : svc_ctx->tcb_pipe[PIPE_READ]; - fd = fd > svc_ctx->evt_pipe[PIPE_READ] ? fd : svc_ctx->evt_pipe[PIPE_READ]; - fd += 1; - while (1) { - FD_ZERO(&set); - FD_SET(svc_ctx->fd, &set); - FD_SET(svc_ctx->tcb_pipe[PIPE_READ], &set); - FD_SET(svc_ctx->evt_pipe[PIPE_READ], &set); + fd = find_max_fd(svc_ctx); + update_fdset(svc_ctx, &set); ret = select(fd, &set, NULL, NULL, NULL); if (ret < 0) { @@ -446,6 +539,12 @@ static void *server_main(void *data) break; } + /*! + * \note + * Invoke the service thread main, to notify the termination of a TCB + */ + ret = svc_ctx->service_thread_main(tcb, NULL, svc_ctx->service_thread_data); + DbgPrint("Destroying TCB[%p]\n", tcb); /*! * at this time, the client thread can access this tcb. @@ -481,6 +580,7 @@ static void *server_main(void *data) free(packet_info); } + processing_timer_event(svc_ctx, &set); /* If there is no such triggered FD? */ } @@ -721,4 +821,64 @@ HAPI int service_common_multicast_packet(struct tcb *tcb, struct packet *packet, return 0; } +/*! + * \note + * SERVER THREAD + */ +HAPI struct service_event_item *service_common_add_timer(struct service_context *svc_ctx, double timer, int (*timer_cb)(struct service_context *svc_cx, void *data), void *data) +{ + struct service_event_item *item; + struct itimerspec spec; + + item = calloc(1, sizeof(*item)); + if (!item) { + ErrPrint("Heap: %s\n", strerror(errno)); + return NULL; + } + + item->type = SERVICE_EVENT_TIMER; + item->info.timer.fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC); + if (item->info.timer.fd < 0) { + ErrPrint("Error: %s\n", strerror(errno)); + free(item); + return NULL; + } + + spec.it_interval.tv_sec = (time_t)timer; + spec.it_interval.tv_nsec = (timer - spec.it_interval.tv_sec) * 1000000000; + spec.it_value.tv_sec = 0; + spec.it_value.tv_nsec = 0; + + if (timerfd_settime(item->info.timer.fd, 0, &spec, NULL) < 0) { + ErrPrint("Error: %s\n", strerror(errno)); + close(item->info.timer.fd); + free(item); + return NULL; + } + + item->event_cb = timer_cb; + item->cbdata = data; + + svc_ctx->event_list = eina_list_append(svc_ctx->event_list, item); + return item; +} + +/*! + * \note + * SERVER THREAD + */ +HAPI int service_common_del_timer(struct service_context *svc_ctx, struct service_event_item *item) +{ + if (!eina_list_data_find(svc_ctx->event_list, item)) { + ErrPrint("Invalid event item\n"); + return -EINVAL; + } + + svc_ctx->event_list = eina_list_remove(svc_ctx->event_list, item); + + close(item->info.timer.fd); + free(item); + return 0; +} + /* End of a file */ diff --git a/src/setting.c b/src/setting.c index 94b103a..5f6bdaf 100644 --- a/src/setting.c +++ b/src/setting.c @@ -22,6 +22,7 @@ #include <sys/stat.h> #include <fcntl.h> #include <errno.h> +#include <locale.h> #include <vconf.h> #include <dlog.h> @@ -80,24 +81,91 @@ static void power_off_cb(keynode_t *node, void *user_data) } } +static void region_changed_cb(keynode_t *node, void *user_data) +{ + char *region; + char *r; + + region = vconf_get_str(VCONFKEY_REGIONFORMAT); + if (!region) + return; + + setenv("LC_CTYPE", region, 1); + setenv("LC_NUMERIC", region, 1); + setenv("LC_TIME", region, 1); + setenv("LC_COLLATE", region, 1); + setenv("LC_MONETARY", region, 1); + setenv("LC_PAPER", region, 1); + setenv("LC_NAME", region, 1); + setenv("LC_ADDRESS", region, 1); + setenv("LC_TELEPHONE", region, 1); + setenv("LC_MEASUREMENT", region, 1); + setenv("LC_IDENTIFICATION", region, 1); + + r = setlocale(LC_ALL, ""); + if (r == NULL) + ErrPrint("Failed to change region\n"); + + free(region); +} + +static void lang_changed_cb(keynode_t *node, void *user_data) +{ + char *lang; + char *r; + + lang = vconf_get_str(VCONFKEY_LANGSET); + if (!lang) + return; + + setenv("LANG", lang, 1); + setenv("LC_MESSAGES", lang, 1); + + r = setlocale(LC_ALL, ""); + if (!r) + ErrPrint("Failed to change locale\n"); + + DbgPrint("Locale: %s\n", setlocale(LC_ALL, NULL)); + free(lang); +} + HAPI int setting_init(void) { int ret; ret = vconf_notify_key_changed(VCONFKEY_PM_STATE, lcd_state_cb, NULL); if (ret < 0) - ErrPrint("Failed to add vconf for lock state\n"); + ErrPrint("Failed to add vconf for lock state: %d\n", ret); ret = vconf_notify_key_changed(VCONFKEY_SYSMAN_POWER_OFF_STATUS, power_off_cb, NULL); if (ret < 0) - ErrPrint("Failed to add vconf for power state\n"); + ErrPrint("Failed to add vconf for power state: %d \n", ret); + + ret = vconf_notify_key_changed(VCONFKEY_LANGSET, lang_changed_cb, NULL); + if (ret < 0) + ErrPrint("Failed to add vconf for lang change: %d\n", ret); + ret = vconf_notify_key_changed(VCONFKEY_REGIONFORMAT, region_changed_cb, NULL); + if (ret < 0) + ErrPrint("Failed to add vconf for region change: %d\n", ret); + + lang_changed_cb(NULL, NULL); + region_changed_cb(NULL, NULL); return ret; } HAPI int setting_fini(void) { int ret; + + ret = vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT, region_changed_cb); + if (ret < 0) + ErrPrint("Failed to ignore vconf key (%d)\n", ret); + + ret = vconf_ignore_key_changed(VCONFKEY_LANGSET, lang_changed_cb); + if (ret < 0) + ErrPrint("Failed to ignore vconf key (%d)\n", ret); + ret = vconf_ignore_key_changed(VCONFKEY_PM_STATE, lcd_state_cb); if (ret < 0) ErrPrint("Failed to ignore vconf key (%d)\n", ret); @@ -105,6 +173,7 @@ HAPI int setting_fini(void) ret = vconf_ignore_key_changed(VCONFKEY_SYSMAN_POWER_OFF_STATUS, power_off_cb); if (ret < 0) ErrPrint("Failed to ignore vconf key (%d)\n", ret); + return ret; } diff --git a/src/shortcut_service.c b/src/shortcut_service.c index 73e6999..81b9005 100644 --- a/src/shortcut_service.c +++ b/src/shortcut_service.c @@ -95,6 +95,10 @@ static int service_thread_main(struct tcb *tcb, struct packet *packet, void *dat const char *command; DbgPrint("TCB: %p, Packet: %p\n", tcb, packet); + if (!packet) { + DbgPrint("TCB: %p is terminated\n", tcb); + return 0; + } command = packet_command(packet); if (!command) { @@ -249,7 +249,7 @@ HAPI char *util_replace_string(const char *src, const char *pattern, const char out_sz = strlen(src); ret = strdup(src); if (!ret) { - printf("Heap: %s\n", strerror(errno)); + ErrPrint("Heap: %s\n", strerror(errno)); return NULL; } diff --git a/src/utility_service.c b/src/utility_service.c new file mode 100644 index 0000000..0b7367d --- /dev/null +++ b/src/utility_service.c @@ -0,0 +1,298 @@ +/* + * Copyright 2013 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.1 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <stdio.h> + +#include <Eina.h> + +#include <dlog.h> +#include <aul.h> + +#include <livebox-errno.h> +#include <packet.h> + +#include "service_common.h" +#include "utility_service.h" +#include "debug.h" +#include "util.h" +#include "conf.h" + +#define UTILITY_ADDR "/tmp/.utility.service" +#define SVC_PKG "org.tizen.data-provider-slave.icon" +#define LAUNCH_TIMEOUT 10.0f + +static struct info { + Eina_List *pending_list; + Eina_List *context_list; + struct service_context *svc_ctx; + + struct tcb *svc_daemon; + pid_t svc_pid; + + struct service_event_item *launch_timer; +} s_info = { + .pending_list = NULL, + .context_list = NULL, /*!< \WARN: This is only used for SERVICE THREAD */ + .svc_ctx = NULL, /*!< \WARN: This is only used for MAIN THREAD */ + + .svc_daemon = NULL, + .svc_pid = -1, + + .launch_timer = NULL, +}; + +struct pending_item { + struct tcb *tcb; + struct packet *packet; +}; + +struct context { + struct tcb *tcb; + double seq; +}; + +static inline int put_reply_tcb(struct tcb *tcb, double seq) +{ + struct context *ctx; + + ctx = malloc(sizeof(*ctx)); + if (!ctx) { + ErrPrint("Heap: %s\n", strerror(errno)); + return LB_STATUS_ERROR_MEMORY; + } + + ctx->tcb = tcb; + ctx->seq = seq; + + s_info.context_list = eina_list_append(s_info.context_list, ctx); + return LB_STATUS_SUCCESS; +} + +static inline struct tcb *get_reply_tcb(double seq) +{ + Eina_List *l; + Eina_List *n; + struct context *ctx; + struct tcb *tcb; + + EINA_LIST_FOREACH_SAFE(s_info.context_list, l, n, ctx) { + if (ctx->seq != seq) + continue; + + s_info.context_list = eina_list_remove(s_info.context_list, ctx); + tcb = ctx->tcb; + free(ctx); + return tcb; + } + + return NULL; +} + +static inline int flush_pended_request(void) +{ + /*! + * Flush all pended requests + */ + struct pending_item *item; + int ret; + + EINA_LIST_FREE(s_info.pending_list, item) { + ret = service_common_unicast_packet(s_info.svc_daemon, item->packet); + if (ret < 0) { + struct packet *reply; + reply = packet_create_reply(item->packet, "i", ret); + if (service_common_unicast_packet(item->tcb, reply) < 0) + ErrPrint("Unable to send packet\n"); + packet_destroy(reply); + } else { + put_reply_tcb(item->tcb, packet_seq(item->packet)); + } + packet_unref(item->packet); + free(item); + } + + return 0; +} + +static inline int put_pended_request(struct tcb *tcb, struct packet *packet) +{ + struct pending_item *item; + + item = malloc(sizeof(*item)); + if (!item) { + ErrPrint("Heap: %s\n", strerror(errno)); + return LB_STATUS_ERROR_MEMORY; + } + + item->tcb = tcb; + item->packet = packet_ref(packet); + if (!item->packet) { + free(item); + ErrPrint("Unable to ref packet\n"); + return LB_STATUS_ERROR_FAULT; + } + + s_info.pending_list = eina_list_append(s_info.pending_list, item); + return 0; +} + +static int launch_timeout_cb(struct service_context *svc_ctx, void *data) +{ + struct pending_item *item; + struct packet *reply; + + EINA_LIST_FREE(s_info.pending_list, item) { + reply = packet_create_reply(item->packet, "i", -EFAULT); + if (!reply) { + ErrPrint("Unable to create a packet\n"); + } else { + int ret; + + ret = service_common_unicast_packet(item->tcb, reply); + if (ret < 0) + ErrPrint("Failed to send reply packet: %d\n", ret); + + packet_destroy(reply); + } + + packet_unref(item->packet); + free(item); + } + + s_info.launch_timer = NULL; + return -ECANCELED; /* Delete this timer */ +} + +static int service_thread_main(struct tcb *tcb, struct packet *packet, void *data) +{ + struct packet *reply; + const char *cmd; + int ret; + + if (!packet) { + DbgPrint("TCB %p is terminated\n", tcb); + + if (tcb == s_info.svc_daemon) { + s_info.svc_daemon = NULL; + s_info.svc_pid = -1; + } + + return 0; + } + + cmd = packet_command(packet); + if (!cmd) { + ErrPrint("Invalid packet\n"); + return LB_STATUS_ERROR_INVALID; + } + + switch (packet_type(packet)) { + case PACKET_REQ: + if (s_info.svc_pid < 0) { + s_info.svc_pid = aul_launch_app(SVC_PKG, NULL); + if (s_info.svc_pid > 0) { + s_info.launch_timer = service_common_add_timer(tcb_svc_ctx(tcb), LAUNCH_TIMEOUT, launch_timeout_cb, NULL); + if (!s_info.launch_timer) + ErrPrint("Unable to create launch timer\n"); + } + } + + if (s_info.svc_pid < 0) { + ErrPrint("Failed to launch an app: %s(%d)\n", SVC_PKG, s_info.svc_pid); + ret = LB_STATUS_ERROR_FAULT; + goto reply_out; + } else if (!s_info.svc_daemon) { + ret = put_pended_request(tcb, packet); + if (ret < 0) + goto reply_out; + } else { + ret = service_common_unicast_packet(s_info.svc_daemon, packet); + if (ret <0) + goto reply_out; + + put_reply_tcb(tcb, packet_seq(packet)); + } + + break; + case PACKET_REQ_NOACK: + if (!strcmp(cmd, "service_register")) { + if (s_info.svc_daemon) { + ErrPrint("Service daemon is already prepared\n"); + return LB_STATUS_ERROR_INVALID; + } + + if (s_info.launch_timer) { + service_common_del_timer(tcb_svc_ctx(tcb), s_info.launch_timer); + s_info.launch_timer = NULL; + } + + s_info.svc_daemon = tcb; + flush_pended_request(); + } + break; + case PACKET_ACK: + tcb = get_reply_tcb(packet_seq(packet)); + if (!tcb) { + ErrPrint("Unable to find reply tcb\n"); + } else { + ret = service_common_unicast_packet(tcb, packet); + if (ret < 0) + ErrPrint("Unable to forward the reply packet\n"); + } + break; + default: + ErrPrint("Packet type is not valid[%s]\n", cmd); + return LB_STATUS_ERROR_INVALID; + } + + return LB_STATUS_SUCCESS; + +reply_out: + ErrPrint("Error: %d\n", ret); + reply = packet_create_reply(packet, "i", ret); + if (service_common_unicast_packet(tcb, reply) < 0) + ErrPrint("Unable to send reply packet\n"); + packet_destroy(reply); + return ret; +} + +int utility_service_init(void) +{ + if (s_info.svc_ctx) { + ErrPrint("Already initialized\n"); + return LB_STATUS_ERROR_ALREADY; + } + + s_info.svc_ctx = service_common_create(UTILITY_ADDR, service_thread_main, NULL); + if (!s_info.svc_ctx) { + ErrPrint("Unable to activate service thread\n"); + return LB_STATUS_ERROR_FAULT; + } + + DbgPrint("Successfully initiated\n"); + return LB_STATUS_SUCCESS; +} + +int utility_service_fini(void) +{ + if (!s_info.svc_ctx) + return LB_STATUS_ERROR_INVALID; + + service_common_destroy(s_info.svc_ctx); + DbgPrint("Successfully Finalized\n"); + return LB_STATUS_SUCCESS; +} + +/* End of a file */ |