Sync with the latest code of phone profile
[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         "com.samsung.data-provider-slave.icon"
37 #endif
38
39 #ifndef LAUNCH_TIMEOUT
40 #define LAUNCH_TIMEOUT  10.0f
41 #endif
42
43 #ifndef TTL_TIMEOUT
44 #define TTL_TIMEOUT     30.0f
45 #endif
46
47 static struct info {
48         Eina_List *pending_list;
49         Eina_List *context_list;
50         struct service_context *svc_ctx;
51
52         struct tcb *svc_daemon;
53         int svc_daemon_is_launched;
54         int svc_daemon_pid;
55
56         struct service_event_item *launch_timer; 
57         struct service_event_item *delay_launcher;
58         struct service_event_item *ttl_timer;
59 } s_info = {
60         .pending_list = NULL,
61         .context_list = NULL, /*!< \WARN: This is only used for SERVICE THREAD */
62         .svc_ctx = NULL, /*!< \WARN: This is only used for MAIN THREAD */
63
64         .svc_daemon = NULL,
65         .svc_daemon_is_launched = 0,
66         .svc_daemon_pid = -1,
67
68         .launch_timer = NULL,
69         .delay_launcher = NULL,
70         .ttl_timer = NULL,
71 };
72
73 struct pending_item {
74         struct tcb *tcb;
75         struct packet *packet;
76 };
77
78 struct context {
79         struct tcb *tcb;
80         double seq;
81 };
82
83 static int lazy_launcher_cb(struct service_context *svc_ctx, void *data);
84
85 static int put_reply_tcb(struct tcb *tcb, double seq)
86 {
87         struct context *ctx;
88
89         ctx = malloc(sizeof(*ctx));
90         if (!ctx) {
91                 ErrPrint("Heap: %s\n", strerror(errno));
92                 return LB_STATUS_ERROR_MEMORY;
93         }
94
95         ctx->tcb = tcb;
96         ctx->seq = seq;
97
98         s_info.context_list = eina_list_append(s_info.context_list, ctx);
99
100         return LB_STATUS_SUCCESS;
101 }
102
103 static inline struct tcb *get_reply_tcb(double seq)
104 {
105         Eina_List *l;
106         Eina_List *n;
107         struct context *ctx;
108         struct tcb *tcb;
109
110         EINA_LIST_FOREACH_SAFE(s_info.context_list, l, n, ctx) {
111                 if (ctx->seq != seq) {
112                         continue;
113                 }
114
115                 s_info.context_list = eina_list_remove(s_info.context_list, ctx);
116                 tcb = ctx->tcb;
117                 DbgFree(ctx);
118                 return tcb;
119         }
120
121         return NULL;
122 }
123
124 static inline int flush_pended_request(void)
125 {
126         /*!
127          * Flush all pended requests
128          */
129         struct pending_item *item;
130         int ret;
131
132         EINA_LIST_FREE(s_info.pending_list, item) {
133                 if (tcb_is_valid(s_info.svc_ctx, s_info.svc_daemon) >= 0) {
134                         ret = service_common_unicast_packet(s_info.svc_daemon, item->packet);
135                 } else {
136                         ret = -EFAULT;
137                 }
138
139                 if (ret < 0) {
140                         if (tcb_is_valid(s_info.svc_ctx, item->tcb) >= 0) {
141                                 struct packet *reply;
142                                 reply = packet_create_reply(item->packet, "i", ret);
143                                 if (service_common_unicast_packet(item->tcb, reply) < 0) {
144                                         ErrPrint("Unable to send packet\n");
145                                 }
146                                 packet_destroy(reply);
147                         }
148                 } else {
149                         put_reply_tcb(item->tcb, packet_seq(item->packet));
150                 }
151                 packet_unref(item->packet);
152                 DbgFree(item);
153         }
154
155         return 0;
156 }
157
158 static inline int put_pended_request(struct tcb *tcb, struct packet *packet)
159 {
160         struct pending_item *item;
161
162         item = malloc(sizeof(*item));
163         if (!item) {
164                 ErrPrint("Heap: %s\n", strerror(errno));
165                 return LB_STATUS_ERROR_MEMORY;
166         }
167
168         item->tcb = tcb;
169         item->packet = packet_ref(packet);
170         if (!item->packet) {
171                 DbgFree(item);
172                 ErrPrint("Unable to ref packet\n");
173                 return LB_STATUS_ERROR_FAULT;
174         }
175
176         s_info.pending_list = eina_list_append(s_info.pending_list, item);
177         return 0;
178 }
179
180 static int launch_timeout_cb(struct service_context *svc_ctx, void *data)
181 {
182         struct pending_item *item;
183         struct packet *reply;
184
185         EINA_LIST_FREE(s_info.pending_list, item) {
186                 if (tcb_is_valid(s_info.svc_ctx, item->tcb) >= 0) {
187                         reply = packet_create_reply(item->packet, "i", -EFAULT);
188                         if (!reply) {
189                                 ErrPrint("Unable to create a packet\n");
190                         } else {
191                                 int ret;
192
193                                 ret = service_common_unicast_packet(item->tcb, reply);
194                                 if (ret < 0) {
195                                         ErrPrint("Failed to send reply packet: %d\n", ret);
196                                 }
197
198                                 packet_destroy(reply);
199                         }
200                 } else {
201                         ErrPrint("TCB is already terminated\n");
202                 }
203
204                 packet_unref(item->packet);
205                 DbgFree(item);
206         }
207
208         s_info.launch_timer = NULL;
209         s_info.svc_daemon_is_launched = 0;
210         s_info.svc_daemon_pid = -1;
211         return -ECANCELED; /* Delete this timer */
212 }
213
214 static int launch_svc(struct service_context *svc_ctx)
215 {
216         pid_t pid;
217         int ret = LB_STATUS_SUCCESS;
218
219         pid = aul_launch_app(SVC_PKG, NULL);
220         switch (pid) {
221         //case AUL_R_EHIDDENFORGUEST:   /**< App hidden for guest mode */
222         case AUL_R_ENOLAUNCHPAD:        /**< no launchpad */
223         case AUL_R_EILLACC:             /**< Illegal Access */
224         case AUL_R_EINVAL:              /**< Invalid argument */
225         case AUL_R_ENOINIT:             /**< AUL handler NOT initialized */
226         case AUL_R_ERROR:               /**< General error */
227                 ErrPrint("Failed to launch an app: %s(%d)\n", SVC_PKG, pid);
228                 ret = LB_STATUS_ERROR_FAULT;
229                 break;
230         case AUL_R_ETIMEOUT:            /**< Timeout */
231         case AUL_R_ECOMM:               /**< Comunication Error */
232         case AUL_R_ETERMINATING:        /**< application terminating */
233         case AUL_R_ECANCELED:           /**< Operation canceled */
234                 /* Need time to launch app again */
235                 ErrPrint("Terminating now, try to launch this after few sec later: %s(%d)\n", SVC_PKG, pid);
236                 s_info.svc_daemon_is_launched = 1;
237                 s_info.delay_launcher = service_common_add_timer(svc_ctx, LAUNCH_TIMEOUT, lazy_launcher_cb, NULL);
238                 if (!s_info.delay_launcher) {
239                         ErrPrint("Unable to add delay launcher\n");
240                         ret = LB_STATUS_ERROR_FAULT;
241                 }
242                 break;
243         case AUL_R_LOCAL:               /**< Launch by himself */
244         case AUL_R_OK:                  /**< General success */
245         default:
246                 DbgPrint("Launched: %s(%d)\n", SVC_PKG, pid);
247                 s_info.svc_daemon_is_launched = 1;
248                 s_info.svc_daemon_pid = pid;
249                 s_info.launch_timer = service_common_add_timer(svc_ctx, LAUNCH_TIMEOUT, launch_timeout_cb, NULL);
250                 if (!s_info.launch_timer) {
251                         ErrPrint("Unable to create launch timer\n");
252                 }
253         }
254
255         return ret;
256 }
257
258 static int lazy_launcher_cb(struct service_context *svc_ctx, void *data)
259 {
260         s_info.delay_launcher = NULL;
261
262         (void)launch_svc(svc_ctx);
263         return -ECANCELED;
264 }
265
266 static int ttl_timer_cb(struct service_context *svc_ctx, void *data)
267 {
268         DbgPrint("TTL Timer is expired: PID(%d)\n", s_info.svc_daemon_pid);
269         (void)aul_terminate_pid(s_info.svc_daemon_pid);
270
271         s_info.ttl_timer = NULL;
272         s_info.svc_daemon_is_launched = 0;
273         s_info.svc_daemon_pid = -1;
274         s_info.svc_daemon = NULL;
275         return -ECANCELED;
276 }
277
278 static int service_thread_main(struct tcb *tcb, struct packet *packet, void *data)
279 {
280         struct packet *reply;
281         const char *cmd;
282         int ret;
283
284         if (!packet) {
285                 DbgPrint("TCB %p is terminated (NIL packet), %d\n", tcb, s_info.svc_daemon_pid);
286
287                 if (tcb == s_info.svc_daemon) {
288                         s_info.svc_daemon = NULL;
289                         s_info.svc_daemon_is_launched = 0;
290                         s_info.svc_daemon_pid = -1;
291
292                         if (s_info.ttl_timer) {
293                                 service_common_del_timer(tcb_svc_ctx(tcb), s_info.ttl_timer);
294                                 s_info.ttl_timer = NULL;
295                         }
296                 }
297
298                 return LB_STATUS_SUCCESS;
299         }
300
301         cmd = packet_command(packet);
302         if (!cmd) {
303                 ErrPrint("Invalid packet\n");
304                 return LB_STATUS_ERROR_INVALID;
305         }
306
307         switch (packet_type(packet)) {
308         case PACKET_REQ:
309                 if (!s_info.svc_daemon_is_launched) {
310                         ret = launch_svc(tcb_svc_ctx(tcb));
311                         if (ret != LB_STATUS_SUCCESS) {
312                                 goto reply_out;
313                         }
314                 }
315
316                 if (!s_info.svc_daemon) {
317                         ret = put_pended_request(tcb, packet);
318                         if (ret < 0) {
319                                 goto reply_out;
320                         }
321                 } else if (tcb_is_valid(s_info.svc_ctx, s_info.svc_daemon) >= 0) { 
322                         ret = service_common_unicast_packet(s_info.svc_daemon, packet);
323                         if (ret <0) {
324                                 goto reply_out;
325                         }
326
327                         put_reply_tcb(tcb, packet_seq(packet));
328
329                         if (s_info.ttl_timer && service_common_update_timer(s_info.ttl_timer, TTL_TIMEOUT) < 0) {
330                                 ErrPrint("Failed to update timer\n");
331                         }
332                 }
333
334                 break;
335         case PACKET_REQ_NOACK:
336                 if (!strcmp(cmd, "service_register")) {
337                         if (!s_info.svc_daemon_is_launched) {
338                                 ErrPrint("Service daemon is not launched. but something tries to register a service\n");
339                                 return LB_STATUS_ERROR_INVALID;
340                         }
341
342                         if (s_info.svc_daemon) {
343                                 ErrPrint("Service daemon is already prepared\n");
344                                 return LB_STATUS_ERROR_INVALID;
345                         }
346
347                         if (s_info.launch_timer) {
348                                 service_common_del_timer(tcb_svc_ctx(tcb), s_info.launch_timer);
349                                 s_info.launch_timer = NULL;
350                         }
351
352                         s_info.ttl_timer = service_common_add_timer(tcb_svc_ctx(tcb), TTL_TIMEOUT, ttl_timer_cb, NULL);
353                         if (!s_info.ttl_timer) {
354                                 ErrPrint("Failed to add TTL timer\n");
355                                 if (s_info.svc_daemon_pid > 0) {
356                                         ret = aul_terminate_pid(s_info.svc_daemon_pid);
357                                         ErrPrint("Terminate: %d\n", ret);
358                                         s_info.svc_daemon_pid = -1;
359                                 }
360                                 s_info.svc_daemon_is_launched = 0;
361                                 return LB_STATUS_ERROR_FAULT;
362                         }
363                         DbgPrint("TTL Timer is added: %p\n", s_info.ttl_timer);
364
365                         s_info.svc_daemon = tcb;
366                         flush_pended_request();
367                 }
368                 break;
369         case PACKET_ACK:
370                 tcb = get_reply_tcb(packet_seq(packet));
371                 if (!tcb) {
372                         ErrPrint("Unable to find reply tcb\n");
373                         break;
374                 }
375
376                 if (tcb_is_valid(s_info.svc_ctx, tcb) < 0) {
377                         ErrPrint("TCB is not valid\n");
378                         break;
379                 }
380
381                 ret = service_common_unicast_packet(tcb, packet);
382                 if (ret < 0) {
383                         ErrPrint("Unable to forward the reply packet\n");
384                 }
385                 break;
386         default:
387                 ErrPrint("Packet type is not valid[%s]\n", cmd);
388                 return LB_STATUS_ERROR_INVALID;
389         }
390
391         return LB_STATUS_SUCCESS;
392
393 reply_out:
394         ErrPrint("Error: %d\n", ret);
395         reply = packet_create_reply(packet, "i", ret);
396         if (service_common_unicast_packet(tcb, reply) < 0) {
397                 ErrPrint("Unable to send reply packet\n");
398         }
399         packet_destroy(reply);
400         return ret;
401 }
402
403 int utility_service_init(void)
404 {
405         if (s_info.svc_ctx) {
406                 ErrPrint("Already initialized\n");
407                 return LB_STATUS_ERROR_ALREADY;
408         }
409
410         s_info.svc_ctx = service_common_create(UTILITY_SOCKET, service_thread_main, NULL);
411         if (!s_info.svc_ctx) {
412                 ErrPrint("Unable to activate service thread\n");
413                 return LB_STATUS_ERROR_FAULT;
414         }
415
416         if (smack_fsetlabel(service_common_fd(s_info.svc_ctx), UTILITY_SMACK_LABEL, SMACK_LABEL_IPOUT) != 0) {
417                 if (errno != EOPNOTSUPP) {
418                         ErrPrint("Unable to set SMACK label(%d)\n", errno);
419                         service_common_destroy(s_info.svc_ctx);
420                         s_info.svc_ctx = NULL;
421                         return LB_STATUS_ERROR_FAULT;
422                 }
423         }
424
425         if (smack_fsetlabel(service_common_fd(s_info.svc_ctx), UTILITY_SMACK_LABEL, SMACK_LABEL_IPIN) != 0) {
426                 if (errno != EOPNOTSUPP) {
427                         ErrPrint("Unable to set SMACK label(%d)\n", errno);
428                         service_common_destroy(s_info.svc_ctx);
429                         s_info.svc_ctx = NULL;
430                         return LB_STATUS_ERROR_FAULT;
431                 }
432         }
433
434         DbgPrint("Successfully initiated\n");
435         return LB_STATUS_SUCCESS;
436 }
437
438 int utility_service_fini(void)
439 {
440         if (!s_info.svc_ctx) {
441                 return LB_STATUS_ERROR_INVALID;
442         }
443
444         service_common_destroy(s_info.svc_ctx);
445         s_info.svc_ctx = NULL;
446         DbgPrint("Successfully Finalized\n");
447         return LB_STATUS_SUCCESS;
448 }
449
450 /* End of a file */