Sync with the private repository
[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                 packet_unref(packet);
204                 return LB_STATUS_ERROR_FAULT;
205         }
206
207         command->ret_cb = ret_cb;
208         command->data = data;
209         command->ttl = DEFAULT_TTL;
210         command->type = TYPE_ACK;
211
212         if (urgent)
213                 prepend_command(command);
214         else
215                 push_command(command);
216
217         packet_unref(packet);
218         return LB_STATUS_SUCCESS;
219 }
220
221 int master_rpc_request_only(struct livebox *handler, struct packet *packet)
222 {
223         struct command *command;
224
225         command = create_command(handler, packet);
226         if (!command) {
227                 ErrPrint("Failed to create a command\n");
228                 packet_unref(packet);
229                 return LB_STATUS_ERROR_FAULT;
230         }
231
232         command->ret_cb = NULL;
233         command->data = NULL;
234         command->ttl = 0;
235         command->type = TYPE_NOACK;
236
237         push_command(command);
238         packet_unref(packet);
239         return LB_STATUS_SUCCESS;
240 }
241
242 int master_rpc_clear_fault_package(const char *pkgname)
243 {
244         struct dlist *l;
245         struct dlist *n;
246         struct command *command;
247
248         if (!pkgname)
249                 return LB_STATUS_ERROR_INVALID;
250
251         DbgPrint("Clear requests of the fault package(%s)\n", pkgname);
252
253         dlist_foreach_safe(s_info.cmd_list, l, n, command) {
254                 if (!command->handler)
255                         continue;
256
257                 if (!strcmp(command->handler->pkgname, pkgname)) {
258                         s_info.cmd_list = dlist_remove(s_info.cmd_list, l);
259                         if (command->ret_cb)
260                                 command->ret_cb(command->handler, NULL, command->data);
261
262                         destroy_command(command);
263                 }
264         }
265
266         return 0;
267 }
268
269 int master_rpc_clear_all_request(void)
270 {
271         struct command *command;
272         struct dlist *l;
273         struct dlist *n;
274
275         DbgPrint("Clear all pended requests\n");
276
277         dlist_foreach_safe(s_info.cmd_list, l, n, command) {
278                 s_info.cmd_list = dlist_remove(s_info.cmd_list, l);
279
280                 if (command->ret_cb)
281                         command->ret_cb(command->handler, NULL, command->data);
282
283                 destroy_command(command);
284         }
285
286         return 0;
287 }
288
289 int master_rpc_sync_request(struct packet *packet)
290 {
291         struct packet *result;
292         int ret;
293
294         result = com_core_packet_oneshot_send(client_addr(), packet, 0.0f);
295         if (result) {
296                 if (packet_get(result, "i", &ret) != 1) {
297                         ErrPrint("Invalid result packet\n");
298                         ret = LB_STATUS_ERROR_INVALID;
299                 }
300
301                 packet_unref(result);
302         } else {
303                 ErrPrint("Failed to send a sync request\n");
304                 ret = LB_STATUS_ERROR_FAULT;
305         }
306
307         packet_unref(packet);
308         return ret;
309 }
310
311 /* End of a file */