[Bluetooth][OTP] Add base code for OTP server role
[platform/core/connectivity/bluetooth-frwk.git] / bt-otp / bt-otpserver.c
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
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
18 #include <dlog.h>
19 #include <gio/gio.h>
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stdint.h>
24 #include <time.h>
25 #include <sys/stat.h>
26 #include <langinfo.h>
27 #include <inttypes.h>
28 #include <errno.h>
29
30 #include "bt-otpserver.h"
31 #include "bluetooth-api.h"
32
33
34 #undef LOG_TAG
35 #define LOG_TAG "BLUETOOTH_OTP"
36
37 #define BT_INFO(fmt, arg...) SLOGI(fmt, ##arg)
38 #define BT_ERR(fmt, arg...) SLOGE(fmt, ##arg)
39 #define BT_DBG(fmt, arg...) SLOGD(fmt, ##arg)
40
41 static GMainLoop *main_loop;
42 GDBusNodeInfo *otp_node_info = NULL;
43 static GDBusConnection *conn;
44 static GDBusConnection *g_conn;
45
46 static int property_sub_id = -1;
47 static guint g_owner_id = 0;
48
49 char *directory = NULL;
50
51 static const gchar otp_introspection_xml[] =
52 "<node name='/'>"
53 "       <interface name='org.projectx.otp_service'>"
54 "               <method name='enable'>"
55 "                       <arg type='s' name='directory'/>"
56 "                       <arg type='i' name='status' direction='out'/>"
57 "               </method>"
58 "               <method name='disable'>"
59 "                       <arg type='i' name='status' direction='out'/>"
60 "               </method>"
61 "       </interface>"
62 "</node>";
63
64 void _bt_otp_deinit_event_receiver(void);
65 void _bt_otp_unregister_interface(void);
66
67 void _bt_otp_exit(void)
68 {
69         int ret;
70         BT_DBG("");
71
72         ret = bluetooth_gatt_deinit();
73         if (ret != BLUETOOTH_ERROR_NONE)
74                 BT_ERR("Failed to Deinit GATT %d", ret);
75
76         _bt_otp_deinit_event_receiver();
77
78         _bt_otp_unregister_interface();
79
80         if (main_loop != NULL) {
81                 g_main_loop_quit(main_loop);
82         }
83 }
84
85 static void _bt_otp_method(GDBusConnection *connection,
86                 const gchar *sender,
87                 const gchar *object_path,
88                 const gchar *interface_name,
89                 const gchar *method_name,
90                 GVariant *parameters,
91                 GDBusMethodInvocation *invocation,
92                 gpointer user_data)
93 {
94         BT_DBG("+");
95         int status = BLUETOOTH_ERROR_NONE;
96
97         BT_DBG("Method[%s] Object Path[%s] Interface Name[%s]",
98                         method_name, object_path, interface_name);
99
100         if (g_strcmp0(method_name, "enable") == 0) {
101                 GDir *dir = NULL;
102                 GError *error = NULL;
103                 const gchar *filename = NULL;
104                 GSList *list = NULL;
105
106                 g_variant_get(parameters, "(s)", &directory);
107                 BT_DBG("Directory = [%s]", directory);
108
109                 dir = g_dir_open(directory, 0, &error);
110                 if (!dir) {
111                         BT_ERR("Failed to open directory: %s", error->message);
112                         g_error_free(error);
113                         status = BLUETOOTH_ERROR_INVALID_DIRECTORY;
114                         goto fail;
115                 }
116
117                 while ((filename = g_dir_read_name(dir))) {
118                         list = g_slist_append(list, (gpointer) filename);
119                 }
120
121                 /* TODO: Extract metadata from these objects and cache it in internal structure */
122
123                 /* TODO: Expose all OTS Characteristics via RegisterApplication */
124
125                 /* TODO: Advertise with OTS_UUID */
126 fail:
127                 g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", status));
128
129         } else if (g_strcmp0(method_name, "disable") == 0) {
130                 g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", status));
131                 _bt_otp_exit();
132         }
133         BT_DBG("-");
134 }
135
136 static const GDBusInterfaceVTable otp_method_table = {
137         _bt_otp_method,
138         NULL,
139         NULL,
140 };
141
142 static void _bt_otp_on_bus_acquired(GDBusConnection *connection, const gchar *name, gpointer user_data)
143 {
144         guint object_id;
145         GError *error = NULL;
146
147         BT_DBG("+");
148
149         g_conn = connection;
150
151         object_id = g_dbus_connection_register_object(connection, BT_OTP_OBJECT_PATH,
152                                                 otp_node_info->interfaces[0],
153                                                 &otp_method_table,
154                                                 NULL, NULL, &error);
155         if (object_id == 0) {
156                 BT_ERR("Failed to register method table: %s", error->message);
157                 g_error_free(error);
158                 g_dbus_node_info_unref(otp_node_info);
159         }
160
161         BT_DBG("-");
162 }
163
164 static void _bt_otp_on_name_acquired(GDBusConnection *connection,
165                                         const gchar     *name,
166                                         gpointer user_data)
167 {
168         BT_DBG("");
169 }
170
171 static void _bt_otp_on_name_lost(GDBusConnection *connection,
172                                 const gchar     *name,
173                                 gpointer user_data)
174 {
175         BT_DBG("");
176         g_object_unref(g_conn);
177         g_conn = NULL;
178         g_dbus_node_info_unref(otp_node_info);
179         g_bus_unown_name(g_owner_id);
180 }
181
182 int _bt_otp_register_interface(void)
183 {
184         BT_DBG("+");
185         GError *error = NULL;
186         guint owner_id;
187
188         otp_node_info = g_dbus_node_info_new_for_xml(otp_introspection_xml, &error);
189         if (!otp_node_info) {
190                 BT_ERR("Failed to install: %s", error->message);
191                 return BLUETOOTH_ERROR_INTERNAL;
192         }
193
194         owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
195                                 BT_OTP_SERVICE_NAME,
196                                 G_BUS_NAME_OWNER_FLAGS_NONE,
197                                 _bt_otp_on_bus_acquired, _bt_otp_on_name_acquired, _bt_otp_on_name_lost,
198                                 NULL, NULL);
199         g_owner_id = owner_id;
200         BT_DBG("owner_id is [%d]\n", owner_id);
201
202         BT_DBG("-");
203         return BLUETOOTH_ERROR_NONE;
204 }
205
206 void _bt_otp_unregister_interface(void)
207 {
208         BT_DBG("+");
209
210         g_object_unref(g_conn);
211         g_conn = NULL;
212         g_dbus_node_info_unref(otp_node_info);
213         g_bus_unown_name(g_owner_id);
214
215         BT_DBG("-");
216         return;
217 }
218
219 void _bt_otp_property_event_filter(GDBusConnection *connection,
220                                         const gchar *sender_name,
221                                         const gchar *object_path,
222                                         const gchar *interface_name,
223                                         const gchar *signal_name,
224                                         GVariant *parameters,
225                                         gpointer user_data)
226 {
227         GVariant *value;
228
229         if (signal_name == NULL) {
230                 BT_ERR("Wrong Signal");
231                 return;
232         }
233
234         if (g_strcmp0(signal_name, PROPERTIES_CHANGED) == 0) {
235
236                 g_variant_get(parameters, "(@a{sv}@as)", &value, NULL);
237                 /* TODO: Handle READ/WRITE request from client */
238         }
239 }
240
241 int _bt_otp_init_event_receiver()
242 {
243         BT_DBG("+");
244         GError *error = NULL;
245
246         if (conn == NULL) {
247                 conn =  g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
248                 if (error != NULL) {
249                         BT_ERR("ERROR: Can't get on system bus [%s]", error->message);
250                         g_clear_error(&error);
251                 }
252         }
253
254         property_sub_id = g_dbus_connection_signal_subscribe(conn,
255                 NULL, BT_OTP_INTERFACE_NAME,
256                 PROPERTIES_CHANGED, BT_OTP_OBJECT_PATH, NULL, 0,
257                 _bt_otp_property_event_filter,
258                 NULL, NULL);
259         BT_DBG("property_sub_id = %d", property_sub_id);
260
261         BT_DBG("-");
262         return 0;
263 }
264
265 void _bt_otp_deinit_event_receiver(void)
266 {
267         BT_DBG("+");
268
269         g_dbus_connection_signal_unsubscribe(conn, property_sub_id);
270         conn = NULL;
271
272         BT_DBG("-");
273 }
274
275 static void _bt_otp_sig_handler(int sig)
276 {
277         BT_DBG("+");
278         switch (sig) {
279         case SIGTERM:
280                 BT_DBG("caught signal - sigterm\n");
281                 break;
282         case SIGINT:
283                 BT_DBG("caught signal - sigint\n");
284                 break;
285         case SIGKILL:
286                 BT_DBG("caught signal - sigkill\n");
287                 break;
288         default:
289                 BT_DBG("caught signal %d and ignored\n", sig);
290                 break;
291         }
292         BT_DBG("-");
293 }
294
295 /* OTP Service Main loop */
296 int main(void)
297 {
298         struct sigaction sa;
299         BT_ERR("Starting the bt-otp daemon");
300
301         memset(&sa, 0, sizeof(sa));
302         sa.sa_handler = _bt_otp_sig_handler;
303         sa.sa_flags = SA_SIGINFO;
304         sigaction(SIGINT, &sa, NULL);
305         sigaction(SIGTERM, &sa, NULL);
306         sigaction(SIGKILL, &sa, NULL);
307
308         if (_bt_otp_register_interface() != BLUETOOTH_ERROR_NONE) {
309                 BT_ERR("Fail to register otp service");
310                 return -4;
311         }
312
313         if (_bt_otp_init_event_receiver() != BLUETOOTH_ERROR_NONE) {
314                 BT_ERR("Fail to init event reciever");
315                 return -5;
316         }
317
318         main_loop = g_main_loop_new(NULL, FALSE);
319
320         g_main_loop_run(main_loop);
321
322         BT_DBG("g_main_loop_quit called!");
323
324         if (main_loop != NULL) {
325                 g_main_loop_unref(main_loop);
326         }
327
328         return 0;
329 }