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