tizen 2.4 release
[framework/context/context-common.git] / src / dbus_client.cpp
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
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 <glib.h>
18 #include <gio/gio.h>
19 #include <security-server.h>
20
21 #include <types_internal.h>
22 #include <scope_mutex.h>
23 #include "response_handler.h"
24 #include "dbus_client.h"
25
26 static GDBusConnection *dbus_connection = NULL;
27 static GDBusNodeInfo *dbus_node_info = NULL;
28
29 static const gchar introspection_xml[] =
30         "<node>"
31         "       <interface name='"DBUS_IFACE"'>"
32         "               <method name='"METHOD_RESPOND"'>"
33         "                       <arg type='i' name='"ARG_REQID"' direction='in'/>"
34         "                       <arg type='s' name='"ARG_SUBJECT"' direction='in'/>"
35         "                       <arg type='i' name='"ARG_RESULT_ERR"' direction='in'/>"
36         "                       <arg type='s' name='"ARG_OUTPUT"' direction='in'/>"
37         "               </method>"
38         "       </interface>"
39         "</node>";
40
41 static const char* get_security_cookie()
42 {
43         static char *cookie = NULL;
44         static GMutex cookie_mutex;
45         ctx::scope_mutex sm(&cookie_mutex);
46
47         if (cookie == NULL) {
48                 int raw_size = security_server_get_cookie_size();
49                 IF_FAIL_RETURN_TAG(raw_size > 0, NULL, _E, "Invalid cookie size");
50
51                 int ret;
52                 char raw_cookie[raw_size];
53
54                 ret = security_server_request_cookie(raw_cookie, raw_size);
55                 IF_FAIL_RETURN_TAG(ret >= 0, NULL, _E, "Failed to get the security cookie");
56
57                 cookie = g_base64_encode(reinterpret_cast<guchar*>(raw_cookie), raw_size);
58                 IF_FAIL_RETURN_TAG(cookie, NULL, _E, "Failed to encode the cookie");
59         }
60
61         return cookie;
62 }
63
64 static void handle_response(const gchar *sender, GVariant *param, GDBusMethodInvocation *invocation)
65 {
66         gint req_id = 0;
67         const gchar *subject = NULL;
68         gint error = 0;
69         const gchar *data = NULL;
70
71         g_variant_get(param, "(i&si&s)", &req_id, &subject, &error, &data);
72         _D("[Response] ReqId: %d, Subject: %s, Error: %d", req_id, subject, error);
73
74         ctx::response_handler::deliver(subject, req_id, error, data);
75         g_dbus_method_invocation_return_value(invocation, NULL);
76 }
77
78 static void handle_method_call(GDBusConnection *conn, const gchar *sender,
79                 const gchar *obj_path, const gchar *iface, const gchar *method_name,
80                 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
81 {
82         IF_FAIL_VOID_TAG(STR_EQ(obj_path, DBUS_PATH), _W, "Invalid path: %s", obj_path);
83         IF_FAIL_VOID_TAG(STR_EQ(iface, DBUS_IFACE), _W, "Invalid interface: %s", obj_path);
84
85         if (STR_EQ(method_name, METHOD_RESPOND)) {
86                 handle_response(sender, param, invocation);
87         } else {
88                 _W("Invalid method: %s", method_name);
89         }
90 }
91
92 ctx::dbus_client::dbus_client()
93 {
94 }
95
96 ctx::dbus_client::~dbus_client()
97 {
98         release();
99 }
100
101 bool ctx::dbus_client::init()
102 {
103         static GMutex connection_mutex;
104         ctx::scope_mutex sm(&connection_mutex);
105
106         if (dbus_connection) {
107                 return true;
108         }
109
110         GError *gerr = NULL;
111
112         dbus_node_info = g_dbus_node_info_new_for_xml(introspection_xml, NULL);
113         IF_FAIL_RETURN_TAG(dbus_node_info != NULL, false, _E, "Initialization failed");
114
115         gchar *addr = g_dbus_address_get_for_bus_sync(G_BUS_TYPE_SYSTEM, NULL, &gerr);
116         HANDLE_GERROR(gerr);
117         IF_FAIL_RETURN_TAG(addr != NULL, false, _E, "Getting address failed");
118         _SD("Address: %s", addr);
119
120         dbus_connection = g_dbus_connection_new_for_address_sync(addr,
121                         (GDBusConnectionFlags)(G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT | G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION),
122                         NULL, NULL, &gerr);
123         g_free(addr);
124         HANDLE_GERROR(gerr);
125         IF_FAIL_RETURN_TAG(dbus_connection != NULL, false, _E, "Connection failed");
126
127         GDBusInterfaceVTable vtable;
128         vtable.method_call = handle_method_call;
129         vtable.get_property = NULL;
130         vtable.set_property = NULL;
131
132         guint reg_id = g_dbus_connection_register_object(dbus_connection, DBUS_PATH,
133                         dbus_node_info->interfaces[0], &vtable, NULL, NULL, &gerr);
134         HANDLE_GERROR(gerr);
135         IF_FAIL_RETURN_TAG(reg_id>0, false, _E, "Object registration failed");
136
137         _I("Dbus connection established: %s", g_dbus_connection_get_unique_name(dbus_connection));
138         return true;
139 }
140
141 void ctx::dbus_client::release()
142 {
143         if (dbus_connection) {
144                 g_dbus_connection_flush_sync(dbus_connection, NULL, NULL);
145                 g_dbus_connection_close_sync(dbus_connection, NULL, NULL);
146                 g_object_unref(dbus_connection);
147                 dbus_connection = NULL;
148         }
149
150         if (dbus_node_info) {
151                 g_dbus_node_info_unref(dbus_node_info);
152                 dbus_node_info = NULL;
153         }
154 }
155
156 int ctx::dbus_client::request(
157                 int type, int req_id, const char* subject, const char* input,
158                 std::string* req_result, std::string* data_read)
159 {
160         _D("Requesting: %d, %d, %s", type, req_id, subject);
161
162         if (subject == NULL) {
163                 subject = EMPTY_STRING;
164         }
165
166         if (input == NULL) {
167                 input = EMPTY_JSON_OBJECT;
168         }
169
170         const char *cookie = get_security_cookie();
171         IF_FAIL_RETURN_TAG(cookie, ERR_OPERATION_FAILED, _E, "Cookie generation failed");
172
173         GVariant *param = g_variant_new("(isiss)", type, cookie, req_id, subject, input);
174         IF_FAIL_RETURN_TAG(param, ERR_OUT_OF_MEMORY, _E, "Memory allocation failed");
175
176         GError *err = NULL;
177         GVariant *response = g_dbus_connection_call_sync(dbus_connection, DBUS_DEST, DBUS_PATH, DBUS_IFACE,
178                         METHOD_REQUEST, param, NULL, G_DBUS_CALL_FLAGS_NONE, DBUS_TIMEOUT, NULL, &err);
179         HANDLE_GERROR(err);
180         IF_FAIL_RETURN_TAG(response, ERR_OPERATION_FAILED, _E, "Method call failed");
181
182         gint _error = ERR_OPERATION_FAILED;
183         const gchar *_req_result = NULL;
184         const gchar *_data_read = NULL;
185
186         g_variant_get(response, "(i&s&s)", &_error, &_req_result, &_data_read);
187         if (req_result) {
188                 *req_result = _req_result;
189         }
190         if (data_read) {
191                 *data_read = _data_read;
192         }
193
194         g_variant_unref(response);
195
196         return _error;
197 }
198
199 int ctx::dbus_client::request_with_no_reply(
200                 int type, int req_id, const char* subject, const char* input)
201 {
202         _D("Requesting: %d, %d, %s", type, req_id, subject);
203
204         if (subject == NULL) {
205                 subject = EMPTY_STRING;
206         }
207
208         if (input == NULL) {
209                 input = EMPTY_JSON_OBJECT;
210         }
211
212         const char *cookie = get_security_cookie();
213         IF_FAIL_RETURN_TAG(cookie, ERR_OPERATION_FAILED, _E, "Cookie generation failed");
214
215         GVariant *param = g_variant_new("(isiss)", type, cookie, req_id, subject, input);
216         IF_FAIL_RETURN_TAG(param, ERR_OUT_OF_MEMORY, _E, "Memory allocation failed");
217
218         GError *err = NULL;
219         g_dbus_connection_call(dbus_connection, DBUS_DEST, DBUS_PATH, DBUS_IFACE,
220                         METHOD_REQUEST, param, NULL, G_DBUS_CALL_FLAGS_NONE, DBUS_TIMEOUT, NULL, NULL, &err);
221
222         if (err) {
223                 HANDLE_GERROR(err);
224                 return ERR_OPERATION_FAILED;
225         }
226
227         return ERR_NONE;
228 }