Store the dbus connection while launching the service
[platform/core/context/context-service.git] / src / agent / legacy / DBusServer.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 <signal.h>
18 #include <app_manager.h>
19
20 #include <Types.h>
21 #include <DBusTypes.h>
22 #include "Server.h"
23 #include "ClientRequest.h"
24 #include "access_control/PeerCreds.h"
25 #include "DBusServer.h"
26
27 using namespace ctx;
28
29 static const gchar __introspection_xml[] =
30         "<node>"
31         "       <interface name='" DBUS_IFACE "'>"
32         "               <method name='" METHOD_REQUEST "'>"
33         "                       <arg type='i' name='" ARG_REQTYPE "' direction='in'/>"
34         "                       <arg type='s' name='" ARG_COOKIE "' direction='in'/>"
35         "                       <arg type='i' name='" ARG_REQID "' direction='in'/>"
36         "                       <arg type='s' name='" ARG_SUBJECT "' direction='in'/>"
37         "                       <arg type='s' name='" ARG_INPUT "' direction='in'/>"
38         "                       <arg type='i' name='" ARG_RESULT_ERR "' direction='out'/>"
39         "                       <arg type='s' name='" ARG_RESULT_ADD "' direction='out'/>"
40         "                       <arg type='s' name='" ARG_OUTPUT "' direction='out'/>"
41         "               </method>"
42         "               <method name='" METHOD_CHK_PRIV_APPLAUNCH "'>"
43         "                       <arg type='i' name='" ARG_RESULT_ERR "' direction='out'/>"
44         "               </method>"
45         "               <method name='" METHOD_CHK_PRIV_CALL "'>"
46         "                       <arg type='i' name='" ARG_RESULT_ERR "' direction='out'/>"
47         "               </method>"
48         "               <method name='" METHOD_CHK_PRIV_NOTIFICATION "'>"
49         "                       <arg type='i' name='" ARG_RESULT_ERR "' direction='out'/>"
50         "               </method>"
51         "       </interface>"
52         "</node>";
53
54 DBusServer *DBusServer::__theInstance = NULL;
55
56 DBusServer::DBusServer() :
57         __owner(-1),
58         __connection(NULL),
59         __nodeInfo(NULL)
60 {
61 }
62
63 DBusServer::~DBusServer()
64 {
65         __release();
66 }
67
68 void DBusServer::__processRequest(const char *sender, GVariant *param, GDBusMethodInvocation *invocation)
69 {
70         gint reqType = 0;
71         const gchar *cookie = NULL;
72         gint reqId = 0;
73         const gchar *subject = NULL;
74         const gchar *input = NULL;
75
76         g_variant_get(param, "(i&si&s&s)", &reqType, &cookie, &reqId, &subject, &input);
77         IF_FAIL_VOID_TAG(reqType > 0 && reqId > 0 && cookie && subject && input, _E, "Invalid request");
78
79         _I("[%d] ReqId: %d, Subject: %s", reqType, reqId, subject);
80         _SI("Input: %s", input);
81
82         Credentials *creds = NULL;
83
84         if (!peer_creds::get(__connection, sender, cookie, &creds)) {
85                 _E("Peer credentialing failed");
86                 g_dbus_method_invocation_return_value(invocation, g_variant_new("(iss)", ERR_OPERATION_FAILED, EMPTY_JSON_OBJECT, EMPTY_JSON_OBJECT));
87                 return;
88         }
89
90         ClientRequest *request = new(std::nothrow) ClientRequest(reqType, reqId, subject, input, creds, sender, invocation);
91         if (!request) {
92                 _E("Memory allocation failed");
93                 g_dbus_method_invocation_return_value(invocation, g_variant_new("(iss)", ERR_OPERATION_FAILED, EMPTY_JSON_OBJECT, EMPTY_JSON_OBJECT));
94                 delete creds;
95                 return;
96         }
97
98         Server::sendRequest(request);
99 }
100
101 void DBusServer::__reply(GDBusMethodInvocation *invocation, int error)
102 {
103         g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", error));
104 }
105
106 void DBusServer::__onMethodCalled(GDBusConnection *conn, const gchar *sender,
107                 const gchar *path, const gchar *iface, const gchar *name,
108                 GVariant *param, GDBusMethodInvocation *invocation, gpointer userData)
109 {
110         IF_FAIL_VOID_TAG(STR_EQ(path, DBUS_PATH), _W, "Invalid path: %s", path);
111         IF_FAIL_VOID_TAG(STR_EQ(iface, DBUS_IFACE), _W, "Invalid interface: %s", path);
112
113         if (STR_EQ(name, METHOD_REQUEST)) {
114                 __theInstance->__processRequest(sender, param, invocation);
115         } else {
116                 __theInstance->__reply(invocation, ERR_NONE);
117         }
118 }
119
120 void DBusServer::__onBusAcquired(GDBusConnection *conn, const gchar *name, gpointer userData)
121 {
122         GDBusInterfaceVTable vtable;
123         vtable.method_call = __onMethodCalled;
124         vtable.get_property = NULL;
125         vtable.set_property = NULL;
126
127         guint regId = g_dbus_connection_register_object(conn, DBUS_PATH,
128                         __theInstance->__nodeInfo->interfaces[0], &vtable, NULL, NULL, NULL);
129
130         if (regId <= 0) {
131                 _E("Failed to acquire dbus");
132                 raise(SIGTERM);
133         }
134
135         __theInstance->__connection = conn;
136         _I("Dbus connection acquired");
137 }
138
139 void DBusServer::__onNameAcquired(GDBusConnection *conn, const gchar *name, gpointer userData)
140 {
141         _SI("Dbus name acquired: %s", name);
142         Server::activate();
143 }
144
145 void DBusServer::__onNameLost(GDBusConnection *conn, const gchar *name, gpointer userData)
146 {
147         _E("Dbus name lost");
148         raise(SIGTERM);
149 }
150
151 void DBusServer::__onCallDone(GObject *source, GAsyncResult *res, gpointer userData)
152 {
153         _I("Call %u done", *static_cast<unsigned int*>(userData));
154
155         GDBusConnection *conn = G_DBUS_CONNECTION(source);
156         GError *error = NULL;
157         g_dbus_connection_call_finish(conn, res, &error);
158         HANDLE_GERROR(error);
159 }
160
161 bool DBusServer::__init()
162 {
163         __nodeInfo = g_dbus_node_info_new_for_xml(__introspection_xml, NULL);
164         IF_FAIL_RETURN_TAG(__nodeInfo != NULL, false, _E, "Initialization failed");
165
166         __owner = g_bus_own_name(G_BUS_TYPE_SESSION, DBUS_DEST, G_BUS_NAME_OWNER_FLAGS_NONE,
167                         __onBusAcquired, __onNameAcquired, __onNameLost, NULL, NULL);
168
169         __theInstance = this;
170         return true;
171 }
172
173 void DBusServer::__release()
174 {
175         if (__connection) {
176                 g_dbus_connection_flush_sync(__connection, NULL, NULL);
177         }
178
179         if (__owner > 0) {
180                 g_bus_unown_name(__owner);
181                 __owner = 0;
182         }
183
184         if (__connection) {
185                 g_dbus_connection_close_sync(__connection, NULL, NULL);
186                 g_object_unref(__connection);
187                 __connection = NULL;
188         }
189
190         if (__nodeInfo) {
191                 g_dbus_node_info_unref(__nodeInfo);
192                 __nodeInfo = NULL;
193         }
194 }
195
196 void DBusServer::__publish(const char *dest, int reqId, const char *subject, int error, const char *data)
197 {
198         _SI("Publish: %s, %d, %s, %#x, %s", dest, reqId, subject, error, data);
199
200         GVariant *param = g_variant_new("(isis)", reqId, subject, error, data);
201         IF_FAIL_VOID_TAG(param, _E, "Memory allocation failed");
202
203         g_dbus_connection_call(__connection, dest, DBUS_PATH, DBUS_IFACE,
204                         METHOD_RESPOND, param, NULL, G_DBUS_CALL_FLAGS_NONE, DBUS_TIMEOUT, NULL, NULL, NULL);
205 }
206
207 void DBusServer::__call(const char *dest, const char *obj, const char *iface, const char *method, GVariant *param)
208 {
209         static unsigned int callCount = 0;
210         ++callCount;
211
212         _SI("Call %u: %s, %s, %s.%s", callCount, dest, obj, iface, method);
213
214         g_dbus_connection_call(__connection, dest, obj, iface, method, param, NULL,
215                         G_DBUS_CALL_FLAGS_NONE, DBUS_TIMEOUT, NULL, __onCallDone, &callCount);
216 }
217
218 void DBusServer::publish(std::string dest, int reqId, std::string subject, int error, std::string data)
219 {
220         IF_FAIL_VOID_TAG(__theInstance, _E, "Not initialized");
221         __theInstance->__publish(dest.c_str(), reqId, subject.c_str(), error, data.c_str());
222 }
223
224 void DBusServer::call(std::string dest, std::string obj, std::string iface, std::string method, GVariant *param)
225 {
226         IF_FAIL_VOID_TAG(__theInstance, _E, "Not initialized");
227         __theInstance->__call(dest.c_str(), obj.c_str(), iface.c_str(), method.c_str(), param);
228 }