Various patches are applied.
[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 "service_common.h"
27 #include "utility_service.h"
28 #include "debug.h"
29 #include "util.h"
30 #include "conf.h"
31
32 #define UTILITY_ADDR    "/tmp/.utility.service"
33 #define SVC_PKG         "org.tizen.data-provider-slave.icon"
34 #define LAUNCH_TIMEOUT  10.0f
35
36 static struct info {
37         Eina_List *pending_list;
38         Eina_List *context_list;
39         struct service_context *svc_ctx;
40
41         struct tcb *svc_daemon;
42         pid_t svc_pid;
43
44         struct service_event_item *launch_timer; 
45 } s_info = {
46         .pending_list = NULL,
47         .context_list = NULL, /*!< \WARN: This is only used for SERVICE THREAD */
48         .svc_ctx = NULL, /*!< \WARN: This is only used for MAIN THREAD */
49
50         .svc_daemon = NULL,
51         .svc_pid = -1,
52
53         .launch_timer = NULL,
54 };
55
56 struct pending_item {
57         struct tcb *tcb;
58         struct packet *packet;
59 };
60
61 struct context {
62         struct tcb *tcb;
63         double seq;
64 };
65
66 static inline int put_reply_tcb(struct tcb *tcb, double seq)
67 {
68         struct context *ctx;
69
70         ctx = malloc(sizeof(*ctx));
71         if (!ctx) {
72                 ErrPrint("Heap: %s\n", strerror(errno));
73                 return LB_STATUS_ERROR_MEMORY;
74         }
75
76         ctx->tcb = tcb;
77         ctx->seq = seq;
78
79         s_info.context_list = eina_list_append(s_info.context_list, ctx);
80         return LB_STATUS_SUCCESS;
81 }
82
83 static inline struct tcb *get_reply_tcb(double seq)
84 {
85         Eina_List *l;
86         Eina_List *n;
87         struct context *ctx;
88         struct tcb *tcb;
89
90         EINA_LIST_FOREACH_SAFE(s_info.context_list, l, n, ctx) {
91                 if (ctx->seq != seq)
92                         continue;
93
94                 s_info.context_list = eina_list_remove(s_info.context_list, ctx);
95                 tcb = ctx->tcb;
96                 free(ctx);
97                 return tcb;
98         }
99
100         return NULL;
101 }
102
103 static inline int flush_pended_request(void)
104 {
105         /*!
106          * Flush all pended requests
107          */
108         struct pending_item *item;
109         int ret;
110
111         EINA_LIST_FREE(s_info.pending_list, item) {
112                 ret = service_common_unicast_packet(s_info.svc_daemon, item->packet);
113                 if (ret < 0) {
114                         struct packet *reply;
115                         reply = packet_create_reply(item->packet, "i", ret);
116                         if (service_common_unicast_packet(item->tcb, reply) < 0)
117                                 ErrPrint("Unable to send packet\n");
118                         packet_destroy(reply);
119                 } else {
120                         put_reply_tcb(item->tcb, packet_seq(item->packet));
121                 }
122                 packet_unref(item->packet);
123                 free(item);
124         }
125
126         return 0;
127 }
128
129 static inline int put_pended_request(struct tcb *tcb, struct packet *packet)
130 {
131         struct pending_item *item;
132
133         item = malloc(sizeof(*item));
134         if (!item) {
135                 ErrPrint("Heap: %s\n", strerror(errno));
136                 return LB_STATUS_ERROR_MEMORY;
137         }
138
139         item->tcb = tcb;
140         item->packet = packet_ref(packet);
141         if (!item->packet) {
142                 free(item);
143                 ErrPrint("Unable to ref packet\n");
144                 return LB_STATUS_ERROR_FAULT;
145         }
146
147         s_info.pending_list = eina_list_append(s_info.pending_list, item);
148         return 0;
149 }
150
151 static int launch_timeout_cb(struct service_context *svc_ctx, void *data)
152 {
153         struct pending_item *item;
154         struct packet *reply;
155
156         EINA_LIST_FREE(s_info.pending_list, item) {
157                 reply = packet_create_reply(item->packet, "i", -EFAULT);
158                 if (!reply) {
159                         ErrPrint("Unable to create a packet\n");
160                 } else {
161                         int ret;
162
163                         ret = service_common_unicast_packet(item->tcb, reply);
164                         if (ret < 0)
165                                 ErrPrint("Failed to send reply packet: %d\n", ret);
166
167                         packet_destroy(reply);
168                 }
169
170                 packet_unref(item->packet);
171                 free(item);
172         }
173
174         s_info.launch_timer = NULL;
175         return -ECANCELED; /* Delete this timer */
176 }
177
178 static int service_thread_main(struct tcb *tcb, struct packet *packet, void *data)
179 {
180         struct packet *reply;
181         const char *cmd;
182         int ret;
183
184         if (!packet) {
185                 DbgPrint("TCB %p is terminated\n", tcb);
186
187                 if (tcb == s_info.svc_daemon) {
188                         s_info.svc_daemon = NULL;
189                         s_info.svc_pid = -1;
190                 }
191
192                 return 0;
193         }
194
195         cmd = packet_command(packet);
196         if (!cmd) {
197                 ErrPrint("Invalid packet\n");
198                 return LB_STATUS_ERROR_INVALID;
199         }
200
201         switch (packet_type(packet)) {
202         case PACKET_REQ:
203                 if (s_info.svc_pid < 0) {
204                         s_info.svc_pid = aul_launch_app(SVC_PKG, NULL);
205                         if (s_info.svc_pid > 0) {
206                                 s_info.launch_timer = service_common_add_timer(tcb_svc_ctx(tcb), LAUNCH_TIMEOUT, launch_timeout_cb, NULL);
207                                 if (!s_info.launch_timer)
208                                         ErrPrint("Unable to create launch timer\n");
209                         }
210                 }
211
212                 if (s_info.svc_pid < 0) {
213                         ErrPrint("Failed to launch an app: %s(%d)\n", SVC_PKG, s_info.svc_pid);
214                         ret = LB_STATUS_ERROR_FAULT;
215                         goto reply_out;
216                 } else if (!s_info.svc_daemon) {
217                         ret = put_pended_request(tcb, packet);
218                         if (ret < 0)
219                                 goto reply_out;
220                 } else {
221                         ret = service_common_unicast_packet(s_info.svc_daemon, packet);
222                         if (ret <0)
223                                 goto reply_out;
224
225                         put_reply_tcb(tcb, packet_seq(packet));
226                 }
227
228                 break;
229         case PACKET_REQ_NOACK:
230                 if (!strcmp(cmd, "service_register")) {
231                         if (s_info.svc_daemon) {
232                                 ErrPrint("Service daemon is already prepared\n");
233                                 return LB_STATUS_ERROR_INVALID;
234                         }
235
236                         if (s_info.launch_timer) {
237                                 service_common_del_timer(tcb_svc_ctx(tcb), s_info.launch_timer);
238                                 s_info.launch_timer = NULL;
239                         }
240
241                         s_info.svc_daemon = tcb;
242                         flush_pended_request();
243                 }
244                 break;
245         case PACKET_ACK:
246                 tcb = get_reply_tcb(packet_seq(packet));
247                 if (!tcb) {
248                         ErrPrint("Unable to find reply tcb\n");
249                 } else {
250                         ret = service_common_unicast_packet(tcb, packet);
251                         if (ret < 0)
252                                 ErrPrint("Unable to forward the reply packet\n");
253                 }
254                 break;
255         default:
256                 ErrPrint("Packet type is not valid[%s]\n", cmd);
257                 return LB_STATUS_ERROR_INVALID;
258         }
259
260         return LB_STATUS_SUCCESS;
261
262 reply_out:
263         ErrPrint("Error: %d\n", ret);
264         reply = packet_create_reply(packet, "i", ret);
265         if (service_common_unicast_packet(tcb, reply) < 0)
266                 ErrPrint("Unable to send reply packet\n");
267         packet_destroy(reply);
268         return ret;
269 }
270
271 int utility_service_init(void)
272 {
273         if (s_info.svc_ctx) {
274                 ErrPrint("Already initialized\n");
275                 return LB_STATUS_ERROR_ALREADY;
276         }
277
278         s_info.svc_ctx = service_common_create(UTILITY_ADDR, service_thread_main, NULL);
279         if (!s_info.svc_ctx) {
280                 ErrPrint("Unable to activate service thread\n");
281                 return LB_STATUS_ERROR_FAULT;
282         }
283
284         DbgPrint("Successfully initiated\n");
285         return LB_STATUS_SUCCESS;
286 }
287
288 int utility_service_fini(void)
289 {
290         if (!s_info.svc_ctx)
291                 return LB_STATUS_ERROR_INVALID;
292
293         service_common_destroy(s_info.svc_ctx);
294         DbgPrint("Successfully Finalized\n");
295         return LB_STATUS_SUCCESS;
296 }
297
298 /* End of a file */