Merge branch 'tizen_2.2' of ssh://review.tizendev.org:29418/apps/livebox/data-provide...
[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 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
106                 s_info.context_list = eina_list_remove(s_info.context_list, ctx);
107                 tcb = ctx->tcb;
108                 DbgFree(ctx);
109                 return tcb;
110         }
111
112         return NULL;
113 }
114
115 static inline int flush_pended_request(void)
116 {
117         /*!
118          * Flush all pended requests
119          */
120         struct pending_item *item;
121         int ret;
122
123         EINA_LIST_FREE(s_info.pending_list, item) {
124                 ret = service_common_unicast_packet(s_info.svc_daemon, item->packet);
125                 if (ret < 0) {
126                         struct packet *reply;
127                         reply = packet_create_reply(item->packet, "i", ret);
128                         if (service_common_unicast_packet(item->tcb, reply) < 0) {
129                                 ErrPrint("Unable to send packet\n");
130                         }
131                         packet_destroy(reply);
132                 } else {
133                         put_reply_tcb(item->tcb, packet_seq(item->packet));
134                 }
135                 packet_unref(item->packet);
136                 DbgFree(item);
137         }
138
139         return 0;
140 }
141
142 static inline int put_pended_request(struct tcb *tcb, struct packet *packet)
143 {
144         struct pending_item *item;
145
146         item = malloc(sizeof(*item));
147         if (!item) {
148                 ErrPrint("Heap: %s\n", strerror(errno));
149                 return LB_STATUS_ERROR_MEMORY;
150         }
151
152         item->tcb = tcb;
153         item->packet = packet_ref(packet);
154         if (!item->packet) {
155                 DbgFree(item);
156                 ErrPrint("Unable to ref packet\n");
157                 return LB_STATUS_ERROR_FAULT;
158         }
159
160         s_info.pending_list = eina_list_append(s_info.pending_list, item);
161         return 0;
162 }
163
164 static int launch_timeout_cb(struct service_context *svc_ctx, void *data)
165 {
166         struct pending_item *item;
167         struct packet *reply;
168
169         EINA_LIST_FREE(s_info.pending_list, item) {
170                 reply = packet_create_reply(item->packet, "i", -EFAULT);
171                 if (!reply) {
172                         ErrPrint("Unable to create a packet\n");
173                 } else {
174                         int ret;
175
176                         ret = service_common_unicast_packet(item->tcb, reply);
177                         if (ret < 0) {
178                                 ErrPrint("Failed to send reply packet: %d\n", ret);
179                         }
180
181                         packet_destroy(reply);
182                 }
183
184                 packet_unref(item->packet);
185                 DbgFree(item);
186         }
187
188         s_info.launch_timer = NULL;
189         s_info.svc_daemon_is_launched = 0;
190         return -ECANCELED; /* Delete this timer */
191 }
192
193 static inline int launch_svc(struct service_context *svc_ctx)
194 {
195         pid_t pid;
196         int ret = LB_STATUS_SUCCESS;
197
198         pid = aul_launch_app(SVC_PKG, NULL);
199         switch (pid) {
200         //case AUL_R_EHIDDENFORGUEST:   /**< App hidden for guest mode */
201         case AUL_R_ENOLAUNCHPAD:        /**< no launchpad */
202         case AUL_R_EILLACC:             /**< Illegal Access */
203         case AUL_R_EINVAL:              /**< Invalid argument */
204         case AUL_R_ENOINIT:             /**< AUL handler NOT initialized */
205         case AUL_R_ERROR:               /**< General error */
206                 ErrPrint("Failed to launch an app: %s(%d)\n", SVC_PKG, pid);
207                 ret = LB_STATUS_ERROR_FAULT;
208                 break;
209         case AUL_R_ETIMEOUT:            /**< Timeout */
210         case AUL_R_ECOMM:               /**< Comunication Error */
211         case AUL_R_ETERMINATING:        /**< application terminating */
212         case AUL_R_ECANCELED:           /**< Operation canceled */
213                 /* Need time to launch app again */
214                 ErrPrint("Terminating now, try to launch this after few sec later: %s(%d)\n", SVC_PKG, pid);
215                 s_info.svc_daemon_is_launched = 1;
216                 s_info.delay_launcher = service_common_add_timer(svc_ctx, LAUNCH_TIMEOUT, lazy_launcher_cb, NULL);
217                 if (!s_info.delay_launcher) {
218                         ErrPrint("Unable to add delay launcher\n");
219                         ret = LB_STATUS_ERROR_FAULT;
220                 }
221                 break;
222         case AUL_R_LOCAL:               /**< Launch by himself */
223         case AUL_R_OK:                  /**< General success */
224         default:
225                 DbgPrint("Launched: %s(%d)\n", SVC_PKG, pid);
226                 s_info.svc_daemon_is_launched = 1;
227                 s_info.launch_timer = service_common_add_timer(svc_ctx, LAUNCH_TIMEOUT, launch_timeout_cb, NULL);
228                 if (!s_info.launch_timer) {
229                         ErrPrint("Unable to create launch timer\n");
230                 }
231         }
232
233         return ret;
234 }
235
236 static int lazy_launcher_cb(struct service_context *svc_ctx, void *data)
237 {
238         s_info.svc_daemon_is_launched = launch_svc(svc_ctx) == LB_STATUS_SUCCESS;
239         s_info.delay_launcher = NULL;
240         return -ECANCELED;
241 }
242
243 static int service_thread_main(struct tcb *tcb, struct packet *packet, void *data)
244 {
245         struct packet *reply;
246         const char *cmd;
247         int ret;
248
249         if (!packet) {
250                 DbgPrint("TCB %p is terminated (NIL packet)\n", tcb);
251
252                 if (tcb == s_info.svc_daemon) {
253                         s_info.svc_daemon = NULL;
254                         s_info.svc_daemon_is_launched = 0;
255                 }
256
257                 return LB_STATUS_SUCCESS;
258         }
259
260         cmd = packet_command(packet);
261         if (!cmd) {
262                 ErrPrint("Invalid packet\n");
263                 return LB_STATUS_ERROR_INVALID;
264         }
265
266         switch (packet_type(packet)) {
267         case PACKET_REQ:
268                 if (!s_info.svc_daemon_is_launched) {
269                         ret = launch_svc(tcb_svc_ctx(tcb));
270                         if (ret != LB_STATUS_SUCCESS) {
271                                 goto reply_out;
272                         }
273                 }
274
275                 if (!s_info.svc_daemon) {
276                         ret = put_pended_request(tcb, packet);
277                         if (ret < 0) {
278                                 goto reply_out;
279                         }
280                 } else {
281                         ret = service_common_unicast_packet(s_info.svc_daemon, packet);
282                         if (ret <0) {
283                                 goto reply_out;
284                         }
285
286                         put_reply_tcb(tcb, packet_seq(packet));
287                 }
288
289                 break;
290         case PACKET_REQ_NOACK:
291                 if (!strcmp(cmd, "service_register")) {
292                         if (!s_info.svc_daemon_is_launched) {
293                                 ErrPrint("Service daemon is not launched. but something tries to register a service\n");
294                                 return LB_STATUS_ERROR_INVALID;
295                         }
296
297                         if (s_info.svc_daemon) {
298                                 ErrPrint("Service daemon is already prepared\n");
299                                 return LB_STATUS_ERROR_INVALID;
300                         }
301
302                         if (s_info.launch_timer) {
303                                 service_common_del_timer(tcb_svc_ctx(tcb), s_info.launch_timer);
304                                 s_info.launch_timer = NULL;
305                         }
306
307                         s_info.svc_daemon = tcb;
308                         flush_pended_request();
309                 }
310                 break;
311         case PACKET_ACK:
312                 tcb = get_reply_tcb(packet_seq(packet));
313                 if (!tcb) {
314                         ErrPrint("Unable to find reply tcb\n");
315                 } else {
316                         ret = service_common_unicast_packet(tcb, packet);
317                         if (ret < 0) {
318                                 ErrPrint("Unable to forward the reply packet\n");
319                         }
320                 }
321                 break;
322         default:
323                 ErrPrint("Packet type is not valid[%s]\n", cmd);
324                 return LB_STATUS_ERROR_INVALID;
325         }
326
327         return LB_STATUS_SUCCESS;
328
329 reply_out:
330         ErrPrint("Error: %d\n", ret);
331         reply = packet_create_reply(packet, "i", ret);
332         if (service_common_unicast_packet(tcb, reply) < 0) {
333                 ErrPrint("Unable to send reply packet\n");
334         }
335         packet_destroy(reply);
336         return ret;
337 }
338
339 int utility_service_init(void)
340 {
341         if (s_info.svc_ctx) {
342                 ErrPrint("Already initialized\n");
343                 return LB_STATUS_ERROR_ALREADY;
344         }
345
346         s_info.svc_ctx = service_common_create(UTILITY_SOCKET, service_thread_main, NULL);
347         if (!s_info.svc_ctx) {
348                 ErrPrint("Unable to activate service thread\n");
349                 return LB_STATUS_ERROR_FAULT;
350         }
351
352         if (smack_fsetlabel(service_common_fd(s_info.svc_ctx), UTILITY_SMACK_LABEL, SMACK_LABEL_IPOUT) != 0) {
353                 if (errno != EOPNOTSUPP) {
354                         ErrPrint("Unable to set SMACK label(%d)\n", errno);
355                         service_common_destroy(s_info.svc_ctx);
356                         s_info.svc_ctx = NULL;
357                         return LB_STATUS_ERROR_FAULT;
358                 }
359         }
360
361         if (smack_fsetlabel(service_common_fd(s_info.svc_ctx), UTILITY_SMACK_LABEL, SMACK_LABEL_IPIN) != 0) {
362                 if (errno != EOPNOTSUPP) {
363                         ErrPrint("Unable to set SMACK label(%d)\n", errno);
364                         service_common_destroy(s_info.svc_ctx);
365                         s_info.svc_ctx = NULL;
366                         return LB_STATUS_ERROR_FAULT;
367                 }
368         }
369
370         DbgPrint("Successfully initiated\n");
371         return LB_STATUS_SUCCESS;
372 }
373
374 int utility_service_fini(void)
375 {
376         if (!s_info.svc_ctx) {
377                 return LB_STATUS_ERROR_INVALID;
378         }
379
380         service_common_destroy(s_info.svc_ctx);
381         s_info.svc_ctx = NULL;
382         DbgPrint("Successfully Finalized\n");
383         return LB_STATUS_SUCCESS;
384 }
385
386 /* End of a file */