7e0bf25b5e5065cfffab002ccaf08ab50c35fe2b
[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
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                         ErrPrint("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 out:
177         if (command->ret_cb)
178                 command->ret_cb(command->handler, packet, command->data);
179
180         destroy_command(command);
181         return 0;
182 }
183
184 static inline void push_command(struct command *command)
185 {
186         s_info.cmd_list = dlist_append(s_info.cmd_list, command);
187         master_rpc_check_and_fire_consumer();
188 }
189
190 /*!
191  * \note
192  * "handler" could be NULL
193  */
194 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)
195 {
196         struct command *command;
197
198         command = create_command(handler, packet);
199         if (!command) {
200                 ErrPrint("Failed to create a command\n");
201                 packet_unref(packet);
202                 return LB_STATUS_ERROR_FAULT;
203         }
204
205         command->ret_cb = ret_cb;
206         command->data = data;
207         command->ttl = DEFAULT_TTL;
208         command->type = TYPE_ACK;
209
210         if (urgent)
211                 prepend_command(command);
212         else
213                 push_command(command);
214
215         packet_unref(packet);
216         return LB_STATUS_SUCCESS;
217 }
218
219 int master_rpc_request_only(struct livebox *handler, struct packet *packet)
220 {
221         struct command *command;
222
223         command = create_command(handler, packet);
224         if (!command) {
225                 ErrPrint("Failed to create a command\n");
226                 packet_unref(packet);
227                 return LB_STATUS_ERROR_FAULT;
228         }
229
230         command->ret_cb = NULL;
231         command->data = NULL;
232         command->ttl = 0;
233         command->type = TYPE_NOACK;
234
235         push_command(command);
236         packet_unref(packet);
237         return LB_STATUS_SUCCESS;
238 }
239
240 int master_rpc_clear_fault_package(const char *pkgname)
241 {
242         struct dlist *l;
243         struct dlist *n;
244         struct command *command;
245
246         if (!pkgname)
247                 return LB_STATUS_ERROR_INVALID;
248
249         dlist_foreach_safe(s_info.cmd_list, l, n, command) {
250                 if (!command->handler)
251                         continue;
252
253                 if (!strcmp(command->handler->pkgname, pkgname)) {
254                         s_info.cmd_list = dlist_remove(s_info.cmd_list, l);
255                         if (command->ret_cb)
256                                 command->ret_cb(command->handler, NULL, command->data);
257
258                         destroy_command(command);
259                 }
260         }
261
262         return 0;
263 }
264
265 int master_rpc_clear_all_request(void)
266 {
267         struct command *command;
268         struct dlist *l;
269         struct dlist *n;
270
271         dlist_foreach_safe(s_info.cmd_list, l, n, command) {
272                 s_info.cmd_list = dlist_remove(s_info.cmd_list, l);
273
274                 if (command->ret_cb)
275                         command->ret_cb(command->handler, NULL, command->data);
276
277                 destroy_command(command);
278         }
279
280         return 0;
281 }
282
283 int master_rpc_sync_request(struct packet *packet)
284 {
285         struct packet *result;
286         int ret;
287
288         result = com_core_packet_oneshot_send(client_addr(), packet, 0.0f);
289         if (result) {
290                 if (packet_get(result, "i", &ret) != 1) {
291                         ErrPrint("Invalid result packet\n");
292                         ret = LB_STATUS_ERROR_INVALID;
293                 }
294
295                 packet_unref(result);
296         } else {
297                 ErrPrint("Failed to send a sync request\n");
298                 ret = LB_STATUS_ERROR_FAULT;
299         }
300
301         packet_unref(packet);
302         return ret;
303 }
304
305 /* End of a file */