7236fb18069d28bfb4944fb7f2836ee5f19a31cb
[platform/core/appfw/slp-pkgmgr.git] / comm / comm_client_gdbus.c
1 /*
2  * slp-pkgmgr
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Jayoun Lee <airjany@samsung.com>, Sewook Park <sewook7.park@samsung.com>,
7  * Jaeho Lee <jaeho81.lee@samsung.com>, Shobhit Srivastava <shobhit.s@samsung.com>
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  */
22
23
24 /*
25  * comm_client_gdbus.c
26  * comm_client library using gdbus
27  */
28
29 #include <glib.h>
30 #include <gio/gio.h>
31 #include <stdbool.h>
32 #include <stdio.h>
33 #include <string.h>
34
35 #include <glib.h>
36 #include <gio/gio.h>
37
38 #include "comm_config.h"
39 #include "comm_client.h"
40 #include "comm_debug.h"
41
42 #define COMM_CLIENT_RETRY_MAX 5
43 #define COMM_CLIENT_WAIT_USEC (1000000 / 2) /* 0.5 sec */
44
45 /*******************
46  * ADT description
47  */
48
49 /* Storing status_cb */
50 struct signal_callback_data {
51         int type;
52         status_cb cb;
53         void *cb_data;
54 };
55
56 /* comm_client ADT */
57 struct comm_client {
58         guint subscription_id;
59         GDBusConnection *conn;
60         struct signal_callback_data *sig_cb_data;
61 };
62
63 static int __get_signal_type(const char *name)
64 {
65         if (name == NULL)
66                 return -1;
67
68         if (strcmp(name, COMM_STATUS_BROADCAST_SIGNAL_STATUS) == 0)
69                 return COMM_STATUS_BROADCAST_ALL;
70         else if (strcmp(name, COMM_STATUS_BROADCAST_EVENT_INSTALL) == 0)
71                 return COMM_STATUS_BROADCAST_INSTALL;
72         else if (strcmp(name, COMM_STATUS_BROADCAST_EVENT_UNINSTALL) == 0)
73                 return COMM_STATUS_BROADCAST_UNINSTALL;
74         else if (strcmp(name, COMM_STATUS_BROADCAST_EVENT_MOVE) == 0)
75                 return COMM_STATUS_BROADCAST_MOVE;
76         else if (strcmp(name, COMM_STATUS_BROADCAST_EVENT_INSTALL_PROGRESS) == 0)
77                 return COMM_STATUS_BROADCAST_INSTALL_PROGRESS;
78         else if (strcmp(name, COMM_STATUS_BROADCAST_EVENT_UPGRADE) == 0)
79                 return COMM_STATUS_BROADCAST_UPGRADE;
80         else if (strcmp(name, COMM_STATUS_BROADCAST_EVENT_GET_SIZE) == 0)
81                 return COMM_STATUS_BROADCAST_GET_SIZE;
82         else
83                 return -1;
84 }
85
86 /**
87  * signal handler filter
88  * Filter signal, and run user callback
89  */
90 void _on_signal_handle_filter(GDBusConnection *conn,
91                 const gchar *sender_name,
92                 const gchar *object_path,
93                 const gchar *interface_name,
94                 const gchar *signal_name,
95                 GVariant *parameters,
96                 gpointer user_data)
97 {
98         if (interface_name && strcmp(interface_name, "org.tizen.pkgmgr.signal")) {
99                 DBG("Interface name did not match. Drop the message");
100                 return;
101         }
102
103         int status_type;
104         /* Values to be received by signal */
105         uid_t target_uid;
106         char *req_id = NULL;
107         char *pkg_type = NULL;
108         char *pkgid = NULL;
109         char *key = NULL;
110         char *val = NULL;
111
112         /* User's signal handler */
113         struct signal_callback_data *sig_cb_data;
114         if (user_data)
115                 sig_cb_data = (struct signal_callback_data *)user_data;
116         else
117                 return;
118
119         status_type = __get_signal_type(signal_name);
120         if (status_type < 0 || !(status_type & sig_cb_data->type))
121                 return;
122
123         g_variant_get(parameters, "(u&s&s&s&s&s)",
124                                 &target_uid, &req_id, &pkg_type, &pkgid, &key, &val);
125
126         /* Run signal callback if exist */
127         if (sig_cb_data && sig_cb_data->cb)
128                 sig_cb_data->cb(sig_cb_data->cb_data, target_uid, req_id,
129                                 pkg_type, pkgid, key, val);
130
131         return;
132 }
133
134 /**
135  * signal_callback_data free function
136  * Just free it!
137  */
138 void _free_sig_cb_data(void *data)
139 {
140         struct signal_callback_data *sig_cb_data = NULL;
141         sig_cb_data = (struct signal_callback_data *)data;
142         free(sig_cb_data);
143 }
144
145 /*******************
146  * API description
147  */
148
149 /**
150  * Create a new comm_client object
151  */
152 comm_client *comm_client_new(void)
153 {
154         GError *error = NULL;
155         comm_client *cc = NULL;
156
157         /* Allocate memory for ADT:comm_client */
158 #if !GLIB_CHECK_VERSION(2,35,0)
159         g_type_init();
160 #endif
161         cc = calloc(1, sizeof(comm_client));
162         if (NULL == cc) {
163                 ERR("No memory");
164                 return NULL;
165         }
166
167         /* Connect to gdbus. Gets shared BUS */
168         cc->conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
169         if (error) {
170                 ERR("gdbus connection error (%s)", error->message);
171                 g_error_free(error);
172                 goto ERROR_CLEANUP;
173         }
174         if (NULL == cc->conn) {
175                 ERR("gdbus connection is not set, even gdbus error isn't raised");
176                 goto ERROR_CLEANUP;
177         }
178         return cc;
179
180  ERROR_CLEANUP:
181         if (cc)
182                 free(cc);
183         return NULL;
184 }
185
186 /**
187  * Free comm_client object
188  */
189 int comm_client_free(comm_client *cc)
190 {
191         if (!cc)
192                 return -1;
193         if (!(cc->conn) || g_dbus_connection_is_closed(cc->conn)) {
194                 ERR("Invalid gdbus connection");
195                 return -2;
196         }
197
198         if (cc->sig_cb_data) {
199                 g_dbus_connection_signal_unsubscribe(cc->conn, cc->subscription_id);
200                 /* TODO: Is it needed to free cc->sig_cb_data here? */
201                 /* _free_sig_cb_data(cc->sig_cb_data); */
202         }
203
204         /* Cleanup ADT */
205         /* flush remaining buffer: blocking mode */
206         g_dbus_connection_flush_sync(cc->conn, NULL, NULL);
207
208         /* Free signal filter if signal callback is exist */
209
210         /* just unref because it is shared BUS.
211         If ref count is 0 it will get free'd automatically
212         */
213         g_object_unref(cc->conn);
214         free(cc);
215
216         return 0;
217 }
218
219 /**
220  * Request a message
221  */
222 int
223 comm_client_request(comm_client *cc, const char *req_id, const int req_type,
224                 const char *pkg_type, const char *pkgid, const char *args,
225                 uid_t uid, int is_block)
226 {
227         GError *error = NULL;
228         gint rc = -1;
229         GDBusProxy *proxy;
230         GVariant *result = NULL;
231         int retry_cnt = 0;
232
233         /* Assign default values if NULL (NULL is not allowed) */
234         if (req_id == NULL)
235                 req_id = "tmp_reqid";
236         if (pkg_type == NULL)
237                 pkg_type = "none";
238         if (pkgid == NULL)
239                 pkgid = "";
240         if (args == NULL)
241                 args = "";
242
243         do {
244                 proxy = g_dbus_proxy_new_sync(cc->conn, G_DBUS_PROXY_FLAGS_NONE, NULL,
245                                 COMM_PKGMGR_DBUS_SERVICE, COMM_PKGMGR_DBUS_OBJECT_PATH,
246                                 COMM_PKGMGR_DBUS_INTERFACE, NULL, &error);
247                 if (proxy == NULL) {
248                         ERR("failed to get proxy object, sleep and retry[%s]", error->message);
249                         g_error_free(error);
250                         error = NULL;
251                         usleep(COMM_CLIENT_WAIT_USEC);
252                         retry_cnt++;
253                         continue;
254                 }
255
256                 result = g_dbus_proxy_call_sync(proxy, "Request", g_variant_new("(sisssi)", req_id, req_type, pkg_type, pkgid, args, uid),
257                                 G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
258                 g_object_unref(proxy);
259                 if (result)
260                         break;
261
262                 ERR("failed to send request, sleep and retry[%s]", error->message);
263                 g_error_free(error);
264                 error = NULL;
265                 usleep(COMM_CLIENT_WAIT_USEC);
266                 retry_cnt++;
267         } while (retry_cnt <= COMM_CLIENT_RETRY_MAX);
268
269         if (result == NULL)
270                 return -1;
271
272         g_variant_get(result, "(i)", &rc);
273         g_variant_unref(result);
274
275         return rc == 0 ? COMM_RET_OK : COMM_RET_ERROR;
276 }
277
278 /**
279  * Set a callback for status signal
280  */
281 int
282 comm_client_set_status_callback(int comm_status_type, comm_client *cc, status_cb cb, void *cb_data)
283 {
284         int r = COMM_RET_ERROR;
285
286         if (NULL == cc)
287                 return COMM_RET_ERROR;
288
289         /* Create new sig_cb_data */
290         cc->sig_cb_data = calloc(1, sizeof(struct signal_callback_data));
291         if ( cc->sig_cb_data ) {
292                 (cc->sig_cb_data)->type = comm_status_type;
293                 (cc->sig_cb_data)->cb = cb;
294                 (cc->sig_cb_data)->cb_data = cb_data;
295         } else {
296                 r = COMM_RET_ERROR;
297                 goto ERROR_CLEANUP;
298         }
299         /* Add a filter for signal */
300         cc->subscription_id = g_dbus_connection_signal_subscribe(cc->conn, NULL, "org.tizen.pkgmgr.signal",
301                 NULL, NULL, NULL, G_DBUS_SIGNAL_FLAGS_NONE,
302                 _on_signal_handle_filter, (gpointer)cc->sig_cb_data, _free_sig_cb_data);
303         if (!cc->subscription_id) {
304                 ERR("Failed to add filter\n");
305                 r = COMM_RET_ERROR;
306                 goto ERROR_CLEANUP;
307         }
308
309         return COMM_RET_OK;
310
311  ERROR_CLEANUP:
312         ERR("General error");
313         return r;
314 }
315