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