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