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