031d16a37625c7e53bd4cf07158665a99532a4d5
[platform/core/connectivity/bluetooth-agent.git] / hid-agent / bluetooth-hid-agent.c
1 /*
2  * Copyright (c) 2017 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 <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <signal.h>
22 #include <fcntl.h>
23 #include <aul.h>
24
25 #include "bluetooth-hid-agent.h"
26
27 static GMainLoop *gmain_loop;
28 static char *g_obj_path;
29
30 static GDBusConnection *gdbus_conn;
31 static GDBusProxy *profile_gproxy;
32 static guint interface_added_sig_id;
33 static guint interface_removed_sig_id;
34 static guint bluez_device_sig_id;
35 static guint name_owner_sig_id;
36
37 #define BT_HID_SIG_NUM 3
38 #define HID_DEVICE_UUID "00001124-0000-1000-8000-00805f9b43bf"
39 #define DEFAULT_ADAPTER_OBJECT_PATH "/org/bluez/hci0"
40
41 /*Below Inrospection data is exposed to application from agent*/
42 static const gchar hid_agent_introspection_xml[] =
43 "<node name='/'>"
44 "     <interface name='org.tizen.HidApp'>"
45 "               <method name='RegisterApplication'>"
46 "               </method>"
47 "               <method name='UnregisterApplication'>"
48 "               </method>"
49 "               <method name='IsHidConnected'>"
50 "                       <arg type='b' name='connected' direction='out'/>"
51 "               </method>"
52 "               <method name='IsHidConnectable'>"
53 "                       <arg type='b' name='connectable' direction='out'/>"
54 "               </method>"
55 "     </interface>"
56 "</node>";
57
58 static bt_hid_agent_info_t bt_hid_info = {0,};
59 static gboolean is_hid_connected;
60 static gboolean is_hid_connectable;
61 static struct sigaction bt_hid_sigoldact[BT_HID_SIG_NUM];
62 static int bt_hid_sig_to_handle[] = { SIGABRT, SIGSEGV, SIGTERM };
63
64 static void __bt_hid_agent_sigterm_handler(int signo);
65 static GError *__bt_hid_agent_set_error(bt_hid_agent_error_t error);
66
67 static void __on_log_glib(const gchar *log_domain, GLogLevelFlags log_level,
68                 const gchar *msg, gpointer user_data)
69 {
70         ERR_C("%s", msg);
71 }
72
73 static GQuark __bt_hid_agent_error_quark(void)
74 {
75         FN_START;
76         static GQuark quark;
77         if (!quark)
78                 quark = g_quark_from_static_string("hid-agent");
79
80         return quark;
81 }
82
83 static GError *__bt_hid_agent_set_error(bt_hid_agent_error_t error)
84 {
85         ERR("error[%d]", error);
86
87         switch (error) {
88         case BT_HID_AGENT_ERROR_NOT_AVAILABLE:
89                 return g_error_new(BT_HID_AGENT_ERROR, error,
90                                         BT_ERROR_NOT_AVAILABLE);
91         case BT_HID_AGENT_ERROR_NOT_CONNECTED:
92                 return g_error_new(BT_HID_AGENT_ERROR, error,
93                                         BT_ERROR_NOT_CONNECTED);
94         case BT_HID_AGENT_ERROR_CONNECTION_FAILED:
95                 return g_error_new(BT_HID_AGENT_ERROR, error,
96                                         BT_ERROR_NOT_CONNECTION_FAILED);
97         case BT_HID_AGENT_ERROR_BUSY:
98                 return g_error_new(BT_HID_AGENT_ERROR, error,
99                                         BT_ERROR_BUSY);
100         case BT_HID_AGENT_ERROR_INVALID_PARAM:
101                 return g_error_new(BT_HID_AGENT_ERROR, error,
102                                         BT_ERROR_INVALID_PARAM);
103         case BT_HID_AGENT_ERROR_ALREADY_EXIST:
104                 return g_error_new(BT_HID_AGENT_ERROR, error,
105                                         BT_ERROR_ALREADY_EXIST);
106         case BT_HID_AGENT_ERROR_ALREADY_CONNECTED:
107                 return g_error_new(BT_HID_AGENT_ERROR, error,
108                                         BT_ERROR_ALREADY_CONNECTED);
109         case BT_HID_AGENT_ERROR_NO_MEMORY:
110                 return g_error_new(BT_HID_AGENT_ERROR, error,
111                                         BT_ERROR_NO_MEMORY);
112         case BT_HID_AGENT_ERROR_NO_DATA:
113                 return g_error_new(BT_HID_AGENT_ERROR, error,
114                                         BT_ERROR_NO_DATA);
115         case BT_HID_AGENT_ERROR_I_O_ERROR:
116                 return g_error_new(BT_HID_AGENT_ERROR, error,
117                                         BT_ERROR_I_O_ERROR);
118         case BT_HID_AGENT_ERROR_APPLICATION:
119                 return g_error_new(BT_HID_AGENT_ERROR, error,
120                                         BT_ERROR_OPERATION_NOT_AVAILABLE);
121         case BT_HID_AGENT_ERROR_NOT_ALLOWED:
122                 return g_error_new(BT_HID_AGENT_ERROR, error,
123                                         BT_ERROR_OPERATION_NOT_ALLOWED);
124         case BT_HID_AGENT_ERROR_NOT_SUPPORTED:
125                 return g_error_new(BT_HID_AGENT_ERROR, error,
126                                         BT_ERROR_OPERATION_NOT_SUPPORTED);
127         case BT_HID_AGENT_ERROR_INVALID_FILE_DESCRIPTOR:
128                 return g_error_new(BT_HID_AGENT_ERROR, error,
129                                         BT_ERROR_INVALID_FILE_DESCRIPTOR);
130         case BT_HID_AGENT_ERROR_INTERNAL:
131         default:
132                 return g_error_new(BT_HID_AGENT_ERROR, error,
133                                                 BT_ERROR_INTERNAL);
134         }
135 }
136
137 static void __bt_hid_name_owner_changed_cb(GDBusConnection *connection,
138                                         const gchar *sender_name,
139                                         const gchar *object_path,
140                                         const gchar *interface_name,
141                                         const gchar *signal_name,
142                                         GVariant *parameters,
143                                         gpointer user_data)
144 {
145         char *name_owner = NULL;
146         char *old_owner = NULL;
147         char *new_owner = NULL;
148         int ret = 0;
149
150         if (strcasecmp(signal_name, "NameOwnerChanged") == 0) {
151                 g_variant_get(parameters, "(sss)", &name_owner, &old_owner, &new_owner);
152
153                 ret = _bt_hid_register_application(FALSE, name_owner);
154                 if (ret == BT_HID_AGENT_ERROR_NONE) {
155                         is_hid_connectable = FALSE;
156                         if (name_owner_sig_id > 0) {
157                                 g_dbus_connection_signal_unsubscribe(gdbus_conn,
158                                                         name_owner_sig_id);
159                                 name_owner_sig_id = 0;
160                         }
161                 }
162         }
163 }
164
165 static void __hid_agent_method(GDBusConnection *connection,
166                             const gchar *sender,
167                             const gchar *object_path,
168                             const gchar *interface_name,
169                             const gchar *method_name,
170                             GVariant *parameters,
171                             GDBusMethodInvocation *context,
172                             gpointer user_data)
173 {
174         INFO("method %s", method_name);
175         int ret = 0;
176         GError *err;
177
178         if (g_strcmp0(method_name, "RegisterApplication") == 0) {
179                 DBG("Sender = %s\n", sender);
180
181                 ret = _bt_hid_register_application(TRUE, sender);
182                 if (ret == BT_HID_AGENT_ERROR_NONE) {
183                         is_hid_connectable = TRUE;
184                         if (name_owner_sig_id == 0) {
185                                 name_owner_sig_id = g_dbus_connection_signal_subscribe(gdbus_conn,
186                                                 NULL, NULL, "NameOwnerChanged", NULL, NULL, 0,
187                                                 __bt_hid_name_owner_changed_cb, NULL, NULL);
188                         }
189                 } else {
190                         goto fail;
191                 }
192
193                 g_dbus_method_invocation_return_value(context, NULL);
194         } else if (g_strcmp0(method_name, "UnregisterApplication") == 0) {
195                 DBG("Sender = %s\n", sender);
196
197                 ret = _bt_hid_register_application(FALSE, sender);
198                 if (ret == BT_HID_AGENT_ERROR_NONE) {
199                         is_hid_connectable = FALSE;
200                         if (name_owner_sig_id > 0) {
201                                 g_dbus_connection_signal_unsubscribe(gdbus_conn,
202                                                         name_owner_sig_id);
203                                 name_owner_sig_id = 0;
204                         }
205                 } else {
206                         goto fail;
207                 }
208
209                 g_dbus_method_invocation_return_value(context, NULL);
210         } else if (g_strcmp0(method_name, "IsHidConnected") == 0) {
211                 DBG("Going to call IsHidConnected");
212                 INFO("is_hid_connected : %s",
213                         is_hid_connected ? "Connected" : "Disconnected");
214
215                 g_dbus_method_invocation_return_value(context,
216                                 g_variant_new("(b)", is_hid_connected));
217         } else if (g_strcmp0(method_name, "IsHidConnectable") == 0) {
218                 DBG("Going to call IsHidConnectable");
219                 INFO("is_hid_connectable : %s",
220                         is_hid_connectable ? "Connectable" : "Non-Connectable");
221
222                 g_dbus_method_invocation_return_value(context,
223                                 g_variant_new("(b)", is_hid_connectable));
224         }
225
226         return;
227
228 fail:
229         err = __bt_hid_agent_set_error(ret);
230         g_dbus_method_invocation_return_gerror(context, err);
231         g_error_free(err);
232 }
233
234 static const GDBusInterfaceVTable method_table = {
235         __hid_agent_method,
236         NULL,
237         NULL,
238 };
239
240 static GDBusNodeInfo *__bt_hid_create_method_node_info
241                                         (const gchar *introspection_data)
242 {
243         if (introspection_data == NULL)
244                 return NULL;
245
246         return g_dbus_node_info_new_for_xml(introspection_data, NULL);
247 }
248
249 static GDBusConnection *__bt_hid_get_gdbus_connection(void)
250 {
251         GDBusConnection *local_system_gconn = NULL;
252         GError *err = NULL;
253
254         if (gdbus_conn == NULL) {
255                 gdbus_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
256                 if (!gdbus_conn) {
257                         if (err) {
258                                 ERR("Unable to connect to dbus: %s", err->message);
259                                 g_clear_error(&err);
260                         }
261                         gdbus_conn = NULL;
262                 }
263         } else if (g_dbus_connection_is_closed(gdbus_conn)) {
264                 local_system_gconn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
265
266                 if (!local_system_gconn) {
267                         ERR("Unable to connect to dbus: %s", err->message);
268                         g_clear_error(&err);
269                 }
270
271                 gdbus_conn = local_system_gconn;
272         }
273         return gdbus_conn;
274 }
275
276 static gboolean __bt_hid_register_methods(void)
277 {
278         FN_START;
279         GError *error = NULL;
280         guint object_id;
281         guint owner_id;
282         GDBusNodeInfo *node_info;
283         GDBusConnection *conn;
284
285         owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
286                                 BT_HID_SERVICE_NAME,
287                                 G_BUS_NAME_OWNER_FLAGS_NONE,
288                                 NULL, NULL, NULL,
289                                 NULL, NULL);
290
291         DBG("owner_id is [%d]", owner_id);
292
293         conn = __bt_hid_get_gdbus_connection();
294         if (!conn) {
295                 ERR("Unable to get connection");
296                 return FALSE;
297         }
298
299         node_info = __bt_hid_create_method_node_info(hid_agent_introspection_xml);
300         if (node_info == NULL)
301                 return FALSE;
302
303         object_id = g_dbus_connection_register_object(conn,
304                                                 BT_HID_AGENT_OBJECT_PATH,
305                                                 node_info->interfaces[0],
306                                                 &method_table,
307                                                 NULL, NULL, &error);
308         g_dbus_node_info_unref(node_info);
309         if (object_id == 0) {
310                 if (error != NULL) {
311                         ERR("Failed to register: %s", error->message);
312                         g_error_free(error);
313                 }
314                 return FALSE;
315         }
316
317         FN_END;
318         return TRUE;
319 }
320
321 static GDBusProxy *__bt_hid_gdbus_init_profile_proxy(void)
322 {
323         FN_START;
324
325         GDBusProxy *proxy;
326         GError *err = NULL;
327         GDBusConnection *conn;
328
329         conn = __bt_hid_get_gdbus_connection();
330         if (!conn) {
331                 ERR("Unable to get connection");
332                 return NULL;
333         }
334
335         proxy =  g_dbus_proxy_new_sync(conn,
336                         G_DBUS_PROXY_FLAGS_NONE, NULL,
337                         BLUEZ_SERVICE_NAME, "/org/bluez",
338                         BLUEZ_PROFILE_MGMT_INTERFACE, NULL, &err);
339
340         if (!proxy) {
341                 if (err) {
342                         ERR("Unable to create proxy: %s", err->message);
343                          g_clear_error(&err);
344                 }
345                 return NULL;
346         }
347
348         profile_gproxy = proxy;
349
350         FN_END;
351         return proxy;
352 }
353
354 static GDBusProxy *__bt_hid_gdbus_get_profile_proxy(void)
355 {
356         return (profile_gproxy) ? profile_gproxy :
357                                   __bt_hid_gdbus_init_profile_proxy();
358 }
359
360 static GDBusProxy *__bt_hid_gdbus_get_service_proxy(const gchar *service,
361                                 const gchar *path, const gchar *interface)
362 {
363         FN_START;
364
365         GDBusProxy *proxy;
366         GError *err = NULL;
367         GDBusConnection *conn;
368
369         conn = __bt_hid_get_gdbus_connection();
370         if (!conn) {
371                 ERR("Unable to get connection");
372                 return NULL;
373         }
374
375         proxy =  g_dbus_proxy_new_sync(conn,
376                         G_DBUS_PROXY_FLAGS_NONE, NULL,
377                         service, path,
378                         interface, NULL, &err);
379
380         if (!proxy) {
381                 if (err) {
382                         ERR("Unable to create proxy: %s", err->message);
383                          g_clear_error(&err);
384                 }
385                 return NULL;
386         }
387
388         FN_END;
389         return proxy;
390 }
391
392 static GDBusProxy *__bt_hid_gdbus_get_device_proxy(char *object_path)
393 {
394         GDBusConnection *conn;
395         GError *err = NULL;
396         GDBusProxy *device_gproxy;
397
398         conn = __bt_hid_get_gdbus_connection();
399
400         if (conn == NULL)
401                 return NULL;
402
403         device_gproxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE,
404                                                 NULL, BLUEZ_SERVICE_NAME,
405                                                 object_path,
406                                                 BLUEZ_DEVICE_INTERFACE,
407                                                 NULL, &err);
408
409         if (device_gproxy == NULL && err) {
410                 ERR("Unable to create proxy: %s", err->message);
411                 g_clear_error(&err);
412                 return NULL;
413         }
414
415         return device_gproxy;
416 }
417
418 static int __bt_hid_agent_gdbus_method_send(const char *service,
419                                 GVariant *path, const char *interface,
420                                 const char *method)
421 {
422         FN_START;
423
424         GVariant *ret;
425         GDBusProxy *proxy;
426         GError *error = NULL;
427
428         proxy = __bt_hid_gdbus_get_service_proxy(service, g_obj_path, interface);
429         if (!proxy)
430                 return BT_HID_AGENT_ERROR_INTERNAL;
431
432         ret = g_dbus_proxy_call_sync(proxy,
433                                 method, path,
434                                 G_DBUS_CALL_FLAGS_NONE, -1,
435                                 NULL, &error);
436         if (ret == NULL) {
437                 /* dBUS-RPC is failed */
438                 ERR("dBUS-RPC is failed");
439                 if (error != NULL) {
440                         /* dBUS gives error cause */
441                         ERR("D-Bus API failure: errCode[%x], message[%s]",
442                                error->code, error->message);
443
444                         g_clear_error(&error);
445                 }
446                 g_object_unref(proxy);
447                 return BT_HID_AGENT_ERROR_INTERNAL;
448         }
449
450         g_variant_unref(ret);
451         g_object_unref(proxy);
452
453         return BT_HID_AGENT_ERROR_NONE;
454 }
455
456 static void __bt_hid_agent_sigterm_handler(int signo)
457 {
458         GDBusConnection *conn;
459         int i;
460
461         ERR_C("***** Signal handler came with signal %d *****", signo);
462
463         conn = __bt_hid_get_gdbus_connection();
464         if (!conn) {
465                 ERR("Unable to get G-DBus connection");
466                 goto done;
467         }
468
469         g_dbus_connection_flush(conn, NULL, NULL, NULL);
470         INFO("Flush g_dbus_connection");
471
472 done:
473         if (gmain_loop) {
474                 g_main_loop_quit(gmain_loop);
475                 INFO("Exiting");
476                 gmain_loop = NULL;
477         } else {
478                 INFO_C("Terminating HID agent");
479                 exit(0);
480         }
481
482         if (signo == SIGTERM)
483                 return;
484
485         for (i = 0; i < BT_HID_SIG_NUM; i++)
486                 sigaction(bt_hid_sig_to_handle[i], &(bt_hid_sigoldact[i]), NULL);
487
488         raise(signo);
489 }
490
491 static int __bt_hid_register_profile(const char *uuid,
492                  const char *name, const char *object)
493 {
494         FN_START;
495         GDBusProxy *proxy;
496         GVariant *ret;
497         GError *error = NULL;
498         GVariantBuilder *builder;
499
500         proxy = __bt_hid_gdbus_get_profile_proxy();
501
502         if (proxy == NULL)
503                 return BT_HID_AGENT_ERROR_INTERNAL;
504
505         builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
506
507         g_variant_builder_add(builder, "{sv}",
508                         "Name", g_variant_new("s",
509                         name));
510
511         g_variant_builder_add(builder, "{sv}",
512                         "PSM", g_variant_new("q", 17));
513
514         ret = g_dbus_proxy_call_sync(proxy, "RegisterProfile",
515                                 g_variant_new("(osa{sv})", BT_HID_BLUEZ_OBJECT_PATH,
516                                         HID_DEVICE_UUID, builder),
517                                 G_DBUS_CALL_FLAGS_NONE, -1,
518                                 NULL, &error);
519
520         g_variant_builder_unref(builder);
521
522         if (ret == NULL) {
523                 /* dBUS-RPC is failed */
524                 ERR("dBUS-RPC is failed");
525                 if (error != NULL) {
526                         /* dBUS gives error cause */
527                         ERR("D-Bus API failure: errCode[%x], message[%s]",
528                                 error->code, error->message);
529                         g_clear_error(&error);
530                 }
531                 return BT_HID_AGENT_ERROR_INTERNAL;
532         }
533         g_variant_unref(ret);
534
535         FN_END;
536         return BT_HID_AGENT_ERROR_NONE;
537 }
538
539 static void __bt_hid_agent_register(void)
540 {
541         FN_START;
542         int ret;
543
544         ret = __bt_hid_register_profile(HID_DEVICE_UUID,
545                                         "HID device", BT_HID_BLUEZ_OBJECT_PATH);
546         if (ret)
547                 ERR("Error in register");
548
549         FN_END;
550         return;
551 }
552
553 static void __bt_hid_agent_unregister(void)
554 {
555         FN_START;
556
557         if (g_obj_path) {
558                 __bt_hid_agent_gdbus_method_send(BLUEZ_SERVICE_NAME,
559                                                 g_variant_new("(o)", BT_HID_BLUEZ_OBJECT_PATH),
560                                                 BLUEZ_HID_INTERFACE_NAME,
561                                                 "UnregisterAgent");
562                 g_free(g_obj_path);
563                 g_obj_path = NULL;
564         }
565
566         FN_END;
567         return;
568 }
569
570 static void __bt_hid_agent_filter_cb(GDBusConnection *connection,
571                                                  const gchar *sender_name,
572                                                  const gchar *object_path,
573                                                  const gchar *interface_name,
574                                                  const gchar *signal_name,
575                                                  GVariant *parameters,
576                                                  gpointer user_data)
577 {
578         FN_START;
579         char *path = NULL;
580
581         GVariant *optional_param;
582
583         if (strcasecmp(signal_name, "InterfacesAdded") == 0) {
584
585                 g_variant_get(parameters, "(&o@a{sa{sv}})",
586                                 &path, &optional_param);
587                 if (!path) {
588                         ERR("Invalid adapter path");
589                         return;
590                 }
591
592                 if (strcasecmp(path, DEFAULT_ADAPTER_OBJECT_PATH) == 0) {
593                         g_obj_path = g_strdup(path);
594                         INFO("Adapter Path = [%s]", path);
595                         __bt_hid_agent_register();
596                 }
597         } else if (strcasecmp(signal_name, "InterfacesRemoved") == 0) {
598                 g_variant_get(parameters, "(&o@as)", &path, &optional_param);
599                 if (!path)
600                         __bt_hid_agent_unregister();
601         }
602         FN_END;
603 }
604
605 void _bt_convert_device_path_to_address(const char *device_path,
606                                                 char *device_address)
607 {
608         char address[BT_ADDRESS_STRING_SIZE] = { 0 };
609         char *dev_addr;
610
611         ret_if(device_path == NULL);
612         ret_if(device_address == NULL);
613
614         dev_addr = strstr(device_path, "dev_");
615         if (dev_addr != NULL) {
616                 char *pos = NULL;
617                 dev_addr += 4;
618                 g_strlcpy(address, dev_addr, sizeof(address));
619
620                 while ((pos = strchr(address, '_')) != NULL) {
621                         *pos = ':';
622                 }
623
624                 g_strlcpy(device_address, address, BT_ADDRESS_STRING_SIZE);
625         }
626 }
627
628 static void __bt_hid_device_filter_cb(GDBusConnection *connection,
629                                         const gchar *sender_name,
630                                         const gchar *object_path,
631                                         const gchar *interface_name,
632                                         const gchar *signal_name,
633                                         GVariant *parameters,
634                                         gpointer user_data)
635 {
636         DBG("sender_name = %s, object_path = %s", sender_name, object_path);
637
638          if (strcasecmp(signal_name, "ProfileStateChanged") == 0) {
639                 char *profile_uuid = NULL;
640                 bt_hid_state_t state = 0;
641
642                 g_variant_get(parameters, "(&si)", &profile_uuid, &state);
643                 if (g_strcmp0(profile_uuid, HID_DEVICE_UUID) == 0) {
644                         if (state == BT_HID_STATE_CONNECTED) {
645                                 g_free(bt_hid_info.object_path);
646                                 bt_hid_info.object_path = g_strdup(object_path);
647                                 DBG("device : [%s]", bt_hid_info.object_path);
648                         }
649                         _bt_hid_set_profile_state(state);
650                 }
651         }
652 }
653
654 static int __bt_hid_agent_get_adapter_path(GDBusConnection *conn, char *path)
655 {
656         GError *err = NULL;
657         GDBusProxy *manager_proxy = NULL;
658         GVariant *result = NULL;
659         char *adapter_path = NULL;
660
661         if (conn == NULL)
662                 return BT_HID_AGENT_ERROR_INTERNAL;
663
664         manager_proxy =  g_dbus_proxy_new_sync(conn,
665                         G_DBUS_PROXY_FLAGS_NONE, NULL,
666                         BLUEZ_SERVICE_NAME,
667                         "/",
668                         BT_MANAGER_INTERFACE,
669                         NULL, &err);
670
671         if (!manager_proxy) {
672                 ERR("Unable to create proxy: %s", err->message);
673                 goto fail;
674         }
675
676         result = g_dbus_proxy_call_sync(manager_proxy, "DefaultAdapter", NULL,
677                         G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
678         if (!result) {
679                 if (err != NULL)
680                         ERR("Fail to get DefaultAdapter (Error: %s)", err->message);
681                 else
682                         ERR("Fail to get DefaultAdapter");
683
684                 goto fail;
685         }
686
687         if (g_strcmp0(g_variant_get_type_string(result), "(o)")) {
688                 ERR("Incorrect result\n");
689                 goto fail;
690         }
691
692         g_variant_get(result, "(&o)", &adapter_path);
693
694         if (adapter_path == NULL ||
695                 strlen(adapter_path) >= BT_ADAPTER_OBJECT_PATH_MAX) {
696                 ERR("Adapter path is inproper\n");
697                 goto fail;
698         }
699
700         if (path)
701                 g_strlcpy(path, adapter_path, BT_ADAPTER_OBJECT_PATH_MAX);
702
703         if (g_obj_path == NULL) {
704                 g_obj_path = g_strdup(adapter_path);
705                 INFO("Update g_obj_path [%s]", adapter_path);
706         }
707
708         g_variant_unref(result);
709         g_object_unref(manager_proxy);
710
711         return 0;
712
713 fail:
714         g_clear_error(&err);
715
716         if (result)
717                 g_variant_unref(result);
718
719         if (manager_proxy)
720                 g_object_unref(manager_proxy);
721
722         return BT_HID_AGENT_ERROR_INTERNAL;
723
724 }
725
726 static void __bt_hid_agent_dbus_init(void)
727 {
728         GDBusConnection *conn;
729
730         FN_START;
731
732         conn = __bt_hid_get_gdbus_connection();
733         if (conn == NULL) {
734                 ERR("Error in creating the gdbus connection");
735                 return;
736         }
737         if (!__bt_hid_register_methods()) {
738                 ERR("Error in __bt_hid_register_methods");
739                 return;
740         }
741
742         if (!__bt_hid_agent_get_adapter_path(conn, NULL)) {
743                 __bt_hid_agent_register();
744         }
745
746         interface_added_sig_id = g_dbus_connection_signal_subscribe(conn,
747                                 NULL, BT_MANAGER_INTERFACE, BT_INTERFACES_ADDED, NULL, NULL, 0,
748                                 __bt_hid_agent_filter_cb, NULL, NULL);
749
750         interface_removed_sig_id = g_dbus_connection_signal_subscribe(conn,
751                                 NULL, BT_MANAGER_INTERFACE, BT_INTERFACES_REMOVED, NULL, NULL, 0,
752                                 __bt_hid_agent_filter_cb, NULL, NULL);
753
754         bluez_device_sig_id = g_dbus_connection_signal_subscribe(conn,
755                                 NULL, BLUEZ_DEVICE_INTERFACE, NULL, NULL,
756                                 NULL, 0, __bt_hid_device_filter_cb,
757                                 NULL, NULL);
758
759         _bt_hid_set_profile_state(BT_HID_STATE_DISCONNECTED);
760
761         FN_END;
762 }
763
764 static void __bt_hid_agent_dbus_deinit(void)
765 {
766         if (profile_gproxy) {
767                 g_object_unref(profile_gproxy);
768                 profile_gproxy = NULL;
769         }
770
771         if (gdbus_conn) {
772                 if (interface_added_sig_id > 0)
773                         g_dbus_connection_signal_unsubscribe(gdbus_conn,
774                                                 interface_added_sig_id);
775
776                 if (interface_removed_sig_id > 0)
777                         g_dbus_connection_signal_unsubscribe(gdbus_conn,
778                                                 interface_removed_sig_id);
779
780                 if (bluez_device_sig_id > 0)
781                         g_dbus_connection_signal_unsubscribe(gdbus_conn,
782                                                 bluez_device_sig_id);
783
784                 if (name_owner_sig_id > 0)
785                         g_dbus_connection_signal_unsubscribe(gdbus_conn,
786                                                 name_owner_sig_id);
787
788                 interface_added_sig_id = 0;
789                 interface_removed_sig_id = 0;
790                 bluez_device_sig_id = 0;
791                 name_owner_sig_id = 0;
792
793                 g_object_unref(gdbus_conn);
794                 gdbus_conn = NULL;
795         }
796 }
797
798
799
800
801 bt_hid_agent_error_t __bt_hid_disconnect_profile(void)
802 {
803         FN_START;
804         GDBusProxy *proxy;
805
806         proxy = __bt_hid_gdbus_get_device_proxy(bt_hid_info.object_path);
807
808         if (proxy == NULL) {
809                 ERR("Error while getting proxy");
810                 return BT_HID_AGENT_ERROR_INTERNAL;
811         }
812
813         g_dbus_proxy_call(proxy, "DisconnectProfile",
814                         g_variant_new("(s)", HID_DEVICE_UUID),
815                         G_DBUS_CALL_FLAGS_NONE, 2000,
816                         NULL, NULL, NULL);
817
818         FN_END;
819
820         return BT_HID_AGENT_ERROR_NONE;
821 }
822
823 int main(void)
824 {
825         int i;
826         struct sigaction sa;
827
828
829         INFO_C("### Starting Bluetooth HID agent");
830
831 #if GLIB_VERSION_MIN_REQUIRED < GLIB_VERSION_2_36
832         g_type_init();
833 #endif
834
835         memset(&sa, 0, sizeof(sa));
836         sa.sa_flags = SA_NOCLDSTOP;
837         sa.sa_handler = __bt_hid_agent_sigterm_handler;
838
839         for (i = 0; i < BT_HID_SIG_NUM; i++)
840                 sigaction(bt_hid_sig_to_handle[i], &sa, &(bt_hid_sigoldact[i]));
841
842         g_log_set_default_handler(__on_log_glib, NULL);
843
844         gmain_loop = g_main_loop_new(NULL, FALSE);
845
846         __bt_hid_agent_dbus_init();
847
848         g_main_loop_run(gmain_loop);
849
850         __bt_hid_agent_dbus_deinit();
851
852         if (gmain_loop)
853                 g_main_loop_unref(gmain_loop);
854
855         INFO_C("### Terminating Bluetooth HID agent");
856         return 0;
857 }
858