Update spec
[platform/framework/web/livebox-viewer.git] / src / master_rpc.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
17 #include <stdio.h>
18 #include <gio/gio.h>
19 #include <errno.h>
20 #include <stdlib.h>
21 #include <string.h>
22
23 #include <dlog.h>
24
25 #include <packet.h>
26 #include <com-core_packet.h>
27 #include <livebox-errno.h>
28 #include <livebox-service.h>
29
30 #include "debug.h"
31 #include "dlist.h"
32 #include "livebox.h"
33 #include "livebox_internal.h"
34 #include "master_rpc.h"
35 #include "client.h"
36 #include "util.h"
37
38 #define DEFAULT_TTL 10
39 #define REQUEST_DELAY 10
40
41 struct command {
42         int ttl;
43         struct packet *packet;
44         struct livebox *handler;
45         void (*ret_cb)(struct livebox *handler, const struct packet *result, void *data);
46         void *data;
47         enum {
48                 TYPE_ACK,
49                 TYPE_NOACK
50         } type;
51 };
52
53 int errno;
54
55 static struct {
56         guint cmd_timer;
57         struct dlist *cmd_list;
58 } s_info = {
59         .cmd_timer = 0,
60         .cmd_list = NULL,
61 };
62
63 static int done_cb(pid_t pid, int handle, const struct packet *packet, void *data);
64
65 static inline struct command *pop_command(void)
66 {
67         struct dlist *l;
68         struct command *command;
69
70         l = dlist_nth(s_info.cmd_list, 0);
71         if (!l) {
72                 return NULL;
73         }
74
75         command = dlist_data(l);
76         s_info.cmd_list = dlist_remove(s_info.cmd_list, l);
77         return command;
78 }
79
80 static inline struct command *create_command(struct livebox *handler, struct packet *packet)
81 {
82         struct command *command;
83
84         command = malloc(sizeof(*command));
85         if (!command) {
86                 ErrPrint("Failed to allocate mem for command\n");
87                 return NULL;
88         }
89
90         command->handler = lb_ref(handler);
91         command->packet = packet_ref(packet);
92         return command;
93 }
94
95 static inline void destroy_command(struct command *command)
96 {
97         packet_unref(command->packet);
98         lb_unref(command->handler, 1);
99         free(command);
100 }
101
102 static gboolean cmd_consumer(gpointer user_data)
103 {
104         struct command *command;
105
106         command = pop_command();
107         if (!command) {
108                 s_info.cmd_timer = 0;
109                 return FALSE;
110         }
111
112         /*!
113          * \NOTE:
114          * Item will be deleted in the "done_cb"
115          *
116          * item->param be release by the g_dbus_proxy_call
117          * so to use it again from the done_cb function,
118          * increate the reference counter of the item->param
119          */
120         if (command->type == TYPE_NOACK) {
121                 if (com_core_packet_send_only(client_fd(), command->packet) < 0) {
122                         ErrPrint("Failed to send a packet to master\n");
123                 }
124
125                 destroy_command(command);
126         } else {
127                 if (com_core_packet_async_send(client_fd(), command->packet, 0u, done_cb, command) < 0) {
128                         ErrPrint("Failed to send a packet to master\n");
129                         if (command->ret_cb) {
130                                 command->ret_cb(command->handler, NULL, command->data);
131                         }
132                         destroy_command(command);
133                 }
134         }
135         return TRUE;
136 }
137
138 static inline void prepend_command(struct command *command)
139 {
140         s_info.cmd_list = dlist_prepend(s_info.cmd_list, command);
141         master_rpc_check_and_fire_consumer();
142 }
143
144 void master_rpc_check_and_fire_consumer(void)
145 {
146         if (!s_info.cmd_list || s_info.cmd_timer || client_fd() < 0) {
147                 return;
148         }
149
150         s_info.cmd_timer = g_timeout_add(REQUEST_DELAY, cmd_consumer, NULL);
151         if (!s_info.cmd_timer) {
152                 ErrPrint("Failed to add timer\n");
153         }
154 }
155
156 static int done_cb(pid_t pid, int handle, const struct packet *packet, void *data)
157 {
158         struct command *command;
159         int ret;
160
161         command = data;
162
163         if (!packet) {
164                 /*! \NOTE:
165                  * Release resource even if
166                  * we failed to finish the method call
167                  */
168                 command->ttl--;
169                 if (command->ttl > 0) {
170                         prepend_command(command);
171                         return 0;
172                 }
173
174                 goto out;
175         }
176
177         if (packet_get(packet, "i", &ret) != 1) {
178                 ErrPrint("Invalid result packet\n");
179                 ret = LB_STATUS_ERROR_INVALID;
180         }
181
182 out:
183         if (command->ret_cb) {
184                 command->ret_cb(command->handler, packet, command->data);
185         }
186
187         destroy_command(command);
188         return 0;
189 }
190
191 static inline void push_command(struct command *command)
192 {
193         s_info.cmd_list = dlist_append(s_info.cmd_list, command);
194         master_rpc_check_and_fire_consumer();
195 }
196
197 /*!
198  * \note
199  * "handler" could be NULL
200  */
201 int master_rpc_async_request(struct livebox *handler, struct packet *packet, int urgent, void (*ret_cb)(struct livebox *handler, const struct packet *result, void *data), void *data)
202 {
203         struct command *command;
204
205         command = create_command(handler, packet);
206         if (!command) {
207                 ErrPrint("Failed to create a command\n");
208                 packet_unref(packet);
209                 return LB_STATUS_ERROR_FAULT;
210         }
211
212         command->ret_cb = ret_cb;
213         command->data = data;
214         command->ttl = DEFAULT_TTL;
215         command->type = TYPE_ACK;
216
217         if (urgent) {
218                 prepend_command(command);
219         } else {
220                 push_command(command);
221         }
222
223         packet_unref(packet);
224         return LB_STATUS_SUCCESS;
225 }
226
227 int master_rpc_request_only(struct livebox *handler, struct packet *packet)
228 {
229         struct command *command;
230
231         command = create_command(handler, packet);
232         if (!command) {
233                 ErrPrint("Failed to create a command\n");
234                 packet_unref(packet);
235                 return LB_STATUS_ERROR_FAULT;
236         }
237
238         command->ret_cb = NULL;
239         command->data = NULL;
240         command->ttl = 0;
241         command->type = TYPE_NOACK;
242
243         push_command(command);
244         packet_unref(packet);
245         return LB_STATUS_SUCCESS;
246 }
247
248 int master_rpc_clear_fault_package(const char *pkgname)
249 {
250         struct dlist *l;
251         struct dlist *n;
252         struct command *command;
253
254         if (!pkgname) {
255                 return LB_STATUS_ERROR_INVALID;
256         }
257
258         dlist_foreach_safe(s_info.cmd_list, l, n, command) {
259                 if (!command->handler) {
260                         continue;
261                 }
262
263                 if (!strcmp(command->handler->common->pkgname, pkgname)) {
264                         s_info.cmd_list = dlist_remove(s_info.cmd_list, l);
265                         if (command->ret_cb) {
266                                 command->ret_cb(command->handler, NULL, command->data);
267                         }
268
269                         destroy_command(command);
270                 }
271         }
272
273         return 0;
274 }
275
276 int master_rpc_clear_all_request(void)
277 {
278         struct command *command;
279         struct dlist *l;
280         struct dlist *n;
281
282         dlist_foreach_safe(s_info.cmd_list, l, n, command) {
283                 s_info.cmd_list = dlist_remove(s_info.cmd_list, l);
284
285                 if (command->ret_cb) {
286                         command->ret_cb(command->handler, NULL, command->data);
287                 }
288
289                 destroy_command(command);
290         }
291
292         return 0;
293 }
294
295 int master_rpc_sync_request(struct packet *packet)
296 {
297         struct packet *result;
298         int ret;
299
300         result = com_core_packet_oneshot_send(client_addr(), packet, 0.0f);
301         if (result) {
302                 if (packet_get(result, "i", &ret) != 1) {
303                         ErrPrint("Invalid result packet\n");
304                         ret = LB_STATUS_ERROR_INVALID;
305                 }
306
307                 packet_unref(result);
308         } else {
309                 ErrPrint("Failed to send a sync request\n");
310                 ret = LB_STATUS_ERROR_FAULT;
311         }
312
313         packet_unref(packet);
314         return ret;
315 }
316
317 /* End of a file */