Merge branch 'tizen_2.1' into tizen_2.2
[platform/framework/web/data-provider-master.git] / src / utility_service.c
1 /*
2  * Copyright 2013  Samsung Electronics Co., Ltd
3  *
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
7  *
8  * http://floralicense.org/license/
9  *
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.
15  */
16 #include <stdio.h>
17
18 #include <Eina.h>
19
20 #include <dlog.h>
21 #include <aul.h>
22
23 #include <livebox-errno.h>
24 #include <packet.h>
25
26 #include <sys/smack.h>
27
28 #include "critical_log.h"
29 #include "service_common.h"
30 #include "utility_service.h"
31 #include "debug.h"
32 #include "util.h"
33 #include "conf.h"
34
35 #ifndef SVC_PKG
36 #define SVC_PKG         "org.tizen.data-provider-slave.icon"
37 #endif
38
39 #ifndef LAUNCH_TIMEOUT
40 #define LAUNCH_TIMEOUT  10.0f
41 #endif
42
43 static struct info {
44         Eina_List *pending_list;
45         Eina_List *context_list;
46         struct service_context *svc_ctx;
47
48         struct tcb *svc_daemon;
49         int svc_daemon_is_launched;
50
51         struct service_event_item *launch_timer; 
52         struct service_event_item *delay_launcher;
53 } s_info = {
54         .pending_list = NULL,
55         .context_list = NULL, /*!< \WARN: This is only used for SERVICE THREAD */
56         .svc_ctx = NULL, /*!< \WARN: This is only used for MAIN THREAD */
57
58         .svc_daemon = NULL,
59         .svc_daemon_is_launched = 0,
60
61         .launch_timer = NULL,
62         .delay_launcher = NULL,
63 };
64
65 struct pending_item {
66         struct tcb *tcb;
67         struct packet *packet;
68 };
69
70 struct context {
71         struct tcb *tcb;
72         double seq;
73 };
74
75 static int lazy_launcher_cb(struct service_context *svc_ctx, void *data);
76
77 static inline int put_reply_tcb(struct tcb *tcb, double seq)
78 {
79         struct context *ctx;
80
81         ctx = malloc(sizeof(*ctx));
82         if (!ctx) {
83                 ErrPrint("Heap: %s\n", strerror(errno));
84                 return LB_STATUS_ERROR_MEMORY;
85         }
86
87         ctx->tcb = tcb;
88         ctx->seq = seq;
89
90         s_info.context_list = eina_list_append(s_info.context_list, ctx);
91         return LB_STATUS_SUCCESS;
92 }
93
94 static inline struct tcb *get_reply_tcb(double seq)
95 {
96         Eina_List *l;
97         Eina_List *n;
98         struct context *ctx;
99         struct tcb *tcb;
100
101         EINA_LIST_FOREACH_SAFE(s_info.context_list, l, n, ctx) {
102                 if (ctx->seq != seq)
103                         continue;
104
105                 s_info.context_list = eina_list_remove(s_info.context_list, ctx);
106                 tcb = ctx->tcb;
107                 free(ctx);
108                 return tcb;
109         }
110
111         return NULL;
112 }
113
114 static inline int flush_pended_request(void)
115 {
116         /*!
117          * Flush all pended requests
118          */
119         struct pending_item *item;
120         int ret;
121
122         EINA_LIST_FREE(s_info.pending_list, item) {
123                 ret = service_common_unicast_packet(s_info.svc_daemon, item->packet);
124                 if (ret < 0) {
125                         struct packet *reply;
126                         reply = packet_create_reply(item->packet, "i", ret);
127                         if (service_common_unicast_packet(item->tcb, reply) < 0)
128                                 ErrPrint("Unable to send packet\n");
129                         packet_destroy(reply);
130                 } else {
131                         put_reply_tcb(item->tcb, packet_seq(item->packet));
132                 }
133                 packet_unref(item->packet);
134                 free(item);
135         }
136
137         return 0;
138 }
139
140 static inline int put_pended_request(struct tcb *tcb, struct packet *packet)
141 {
142         struct pending_item *item;
143
144         item = malloc(sizeof(*item));
145         if (!item) {
146                 ErrPrint("Heap: %s\n", strerror(errno));
147                 return LB_STATUS_ERROR_MEMORY;
148         }
149
150         item->tcb = tcb;
151         item->packet = packet_ref(packet);
152         if (!item->packet) {
153                 free(item);
154                 ErrPrint("Unable to ref packet\n");
155                 return LB_STATUS_ERROR_FAULT;
156         }
157
158         s_info.pending_list = eina_list_append(s_info.pending_list, item);
159         return 0;
160 }
161
162 static int launch_timeout_cb(struct service_context *svc_ctx, void *data)
163 {
164         struct pending_item *item;
165         struct packet *reply;
166
167         EINA_LIST_FREE(s_info.pending_list, item) {
168                 reply = packet_create_reply(item->packet, "i", -EFAULT);
169                 if (!reply) {
170                         ErrPrint("Unable to create a packet\n");
171                 } else {
172                         int ret;
173
174                         ret = service_common_unicast_packet(item->tcb, reply);
175                         if (ret < 0)
176                                 ErrPrint("Failed to send reply packet: %d\n", ret);
177
178                         packet_destroy(reply);
179                 }
180
181                 packet_unref(item->packet);
182                 free(item);
183         }
184
185         s_info.launch_timer = NULL;
186         s_info.svc_daemon_is_launched = 0;
187         return -ECANCELED; /* Delete this timer */
188 }
189
190 static inline int launch_svc(struct service_context *svc_ctx)
191 {
192         pid_t pid;
193         int ret = LB_STATUS_SUCCESS;
194
195         pid = aul_launch_app(SVC_PKG, NULL);
196         if (pid > 0) {
197                 s_info.svc_daemon_is_launched = 1;
198                 s_info.launch_timer = service_common_add_timer(svc_ctx, LAUNCH_TIMEOUT, launch_timeout_cb, NULL);
199                 if (!s_info.launch_timer)
200                         ErrPrint("Unable to create launch timer\n");
201         } else if (pid == AUL_R_ETIMEOUT || pid == AUL_R_ECOMM) {
202                 s_info.svc_daemon_is_launched = 1;
203                 CRITICAL_LOG("SVC launch failed with timeout(%d), But waiting response\n", pid);
204                 s_info.launch_timer = service_common_add_timer(svc_ctx, LAUNCH_TIMEOUT, launch_timeout_cb, NULL);
205                 if (!s_info.launch_timer)
206                         ErrPrint("Unable to create launch timer\n");
207         } else if (pid == AUL_R_ETERMINATING) {
208                 /* Need time to launch app again */
209                 ErrPrint("Terminating now, try to launch this after few sec later\n");
210                 s_info.svc_daemon_is_launched = 1;
211                 s_info.delay_launcher = service_common_add_timer(svc_ctx, LAUNCH_TIMEOUT, lazy_launcher_cb, NULL);
212                 if (!s_info.delay_launcher) {
213                         ErrPrint("Unable to add delay launcher\n");
214                         ret = LB_STATUS_ERROR_FAULT;
215                 }
216         } else {
217                 ErrPrint("Failed to launch an app: %s(%d)\n", SVC_PKG, pid);
218                 ret = LB_STATUS_ERROR_FAULT;
219         }
220
221         return ret;
222 }
223
224 static int lazy_launcher_cb(struct service_context *svc_ctx, void *data)
225 {
226         s_info.svc_daemon_is_launched = launch_svc(svc_ctx) == LB_STATUS_SUCCESS;
227         s_info.delay_launcher = NULL;
228         return -ECANCELED;
229 }
230
231 static int service_thread_main(struct tcb *tcb, struct packet *packet, void *data)
232 {
233         struct packet *reply;
234         const char *cmd;
235         int ret;
236
237         if (!packet) {
238                 DbgPrint("TCB %p is terminated (NIL packet)\n", tcb);
239
240                 if (tcb == s_info.svc_daemon) {
241                         s_info.svc_daemon = NULL;
242                         s_info.svc_daemon_is_launched = 0;
243                 }
244
245                 return 0;
246         }
247
248         cmd = packet_command(packet);
249         if (!cmd) {
250                 ErrPrint("Invalid packet\n");
251                 return LB_STATUS_ERROR_INVALID;
252         }
253
254         switch (packet_type(packet)) {
255         case PACKET_REQ:
256                 if (!s_info.svc_daemon_is_launched) {
257                         ret = launch_svc(tcb_svc_ctx(tcb));
258                         if (ret != LB_STATUS_SUCCESS)
259                                 goto reply_out;
260                 }
261
262                 if (!s_info.svc_daemon) {
263                         ret = put_pended_request(tcb, packet);
264                         if (ret < 0)
265                                 goto reply_out;
266                 } else {
267                         ret = service_common_unicast_packet(s_info.svc_daemon, packet);
268                         if (ret <0)
269                                 goto reply_out;
270
271                         put_reply_tcb(tcb, packet_seq(packet));
272                 }
273
274                 break;
275         case PACKET_REQ_NOACK:
276                 if (!strcmp(cmd, "service_register")) {
277                         if (!s_info.svc_daemon_is_launched) {
278                                 ErrPrint("Service daemon is not launched. but something tries to register a service\n");
279                                 return LB_STATUS_ERROR_INVALID;
280                         }
281
282                         if (s_info.svc_daemon) {
283                                 ErrPrint("Service daemon is already prepared\n");
284                                 return LB_STATUS_ERROR_INVALID;
285                         }
286
287                         if (s_info.launch_timer) {
288                                 service_common_del_timer(tcb_svc_ctx(tcb), s_info.launch_timer);
289                                 s_info.launch_timer = NULL;
290                         }
291
292                         s_info.svc_daemon = tcb;
293                         flush_pended_request();
294                 }
295                 break;
296         case PACKET_ACK:
297                 tcb = get_reply_tcb(packet_seq(packet));
298                 if (!tcb) {
299                         ErrPrint("Unable to find reply tcb\n");
300                 } else {
301                         ret = service_common_unicast_packet(tcb, packet);
302                         if (ret < 0)
303                                 ErrPrint("Unable to forward the reply packet\n");
304                 }
305                 break;
306         default:
307                 ErrPrint("Packet type is not valid[%s]\n", cmd);
308                 return LB_STATUS_ERROR_INVALID;
309         }
310
311         return LB_STATUS_SUCCESS;
312
313 reply_out:
314         ErrPrint("Error: %d\n", ret);
315         reply = packet_create_reply(packet, "i", ret);
316         if (service_common_unicast_packet(tcb, reply) < 0)
317                 ErrPrint("Unable to send reply packet\n");
318         packet_destroy(reply);
319         return ret;
320 }
321
322 int utility_service_init(void)
323 {
324         if (s_info.svc_ctx) {
325                 ErrPrint("Already initialized\n");
326                 return LB_STATUS_ERROR_ALREADY;
327         }
328
329         s_info.svc_ctx = service_common_create(UTILITY_SOCKET, service_thread_main, NULL);
330         if (!s_info.svc_ctx) {
331                 ErrPrint("Unable to activate service thread\n");
332                 return LB_STATUS_ERROR_FAULT;
333         }
334
335         if (smack_fsetlabel(service_common_fd(s_info.svc_ctx), UTILITY_SMACK_LABEL, SMACK_LABEL_IPOUT) != 0) {
336                 if (errno != EOPNOTSUPP) {
337                         ErrPrint("Unable to set SMACK label(%d)\n", errno);
338                         service_common_destroy(s_info.svc_ctx);
339                         s_info.svc_ctx = NULL;
340                         return LB_STATUS_ERROR_FAULT;
341                 }
342         }
343
344         if (smack_fsetlabel(service_common_fd(s_info.svc_ctx), UTILITY_SMACK_LABEL, SMACK_LABEL_IPIN) != 0) {
345                 if (errno != EOPNOTSUPP) {
346                         ErrPrint("Unable to set SMACK label(%d)\n", errno);
347                         service_common_destroy(s_info.svc_ctx);
348                         s_info.svc_ctx = NULL;
349                         return LB_STATUS_ERROR_FAULT;
350                 }
351         }
352
353         DbgPrint("Successfully initiated\n");
354         return LB_STATUS_SUCCESS;
355 }
356
357 int utility_service_fini(void)
358 {
359         if (!s_info.svc_ctx)
360                 return LB_STATUS_ERROR_INVALID;
361
362         service_common_destroy(s_info.svc_ctx);
363         s_info.svc_ctx = NULL;
364         DbgPrint("Successfully Finalized\n");
365         return LB_STATUS_SUCCESS;
366 }
367
368 /* End of a file */