diff options
author | Matt Ranostay <matt.ranostay@konsulko.com> | 2017-06-29 20:15:36 -0700 |
---|---|---|
committer | Matt Ranostay <matt.ranostay@konsulko.com> | 2017-06-30 11:59:16 -0700 |
commit | c6c94220fa7a1311cb60a01d4f009fb559d3b720 (patch) | |
tree | 253a0bfaf56d6e29175b44abfcc8572221474261 /binding-bluetooth/bluetooth-agent.c | |
parent | 087d927a058437a3f6379024705534365a403768 (diff) |
binding: bluetooth: make system wide service
Allow Bluetooth binding to be build separately and installed
as a system wide service
Bug-AGL: SPEC-661 SPEC-715
Change-Id: I12feefa2908243aa3bdcb0341f9bc9654c23741e
Signed-off-by: Matt Ranostay <matt.ranostay@konsulko.com>
Diffstat (limited to 'binding-bluetooth/bluetooth-agent.c')
-rw-r--r-- | binding-bluetooth/bluetooth-agent.c | 736 |
1 files changed, 736 insertions, 0 deletions
diff --git a/binding-bluetooth/bluetooth-agent.c b/binding-bluetooth/bluetooth-agent.c new file mode 100644 index 0000000..7193ce5 --- /dev/null +++ b/binding-bluetooth/bluetooth-agent.c @@ -0,0 +1,736 @@ +/* Copyright 2016 ALPS ELECTRIC CO., LTD. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <gio/gio.h> + +#include "bluetooth-agent.h" + +#ifdef AGENT_THREAD + +#include <pthread.h> + +static GMainLoop *agentLoop = NULL; +#endif + +static GDBusConnection *system_conn = NULL; +static gboolean agent_registered = FALSE; +static const char *agent_capability = NULL; +static Agent_RegisterCallback_t agent_RegisterCallback = { 0 }; +static AGENTOrgBluezAgent1 * agnet_interface = NULL; + +static struct Agent_Node *agent_event = NULL; + + +static void agent_event_auto_release(struct Agent_Node *event) +{ + if (NULL == event ){ + return; + } + g_dbus_method_invocation_return_dbus_error (event->invocation, + ERROR_BLUEZ_REJECT, ""); + g_free(event); +} + +/* + * Store the agent event + */ +static void agent_event_new(AGENTOrgBluezAgent1 *object, + GDBusMethodInvocation *invocation, int type) +{ + LOGD("\n"); + if(NULL !=agent_event ) + { + agent_event_auto_release(agent_event); + } + agent_event = g_malloc0(sizeof(struct Agent_Node)); + agent_event->type = type; + agent_event->object = object; + agent_event->invocation = invocation; + +} + + +/* + * agent api + * + * Methods : void Release() + * This method gets called when the service daemon + * unregisters the agent. An agent can use it to do + * cleanup tasks. There is no need to unregister the + * agent, because when this method gets called it has + * already been unregistered. + */ +static gboolean +on_handle_Release (AGENTOrgBluezAgent1 *object, + GDBusMethodInvocation *invocation, + gpointer user_data) +{ + LOGD("\n"); + + //gboolean ret = FALSE; + + if (NULL != agent_RegisterCallback.agent_Release) + { + agent_RegisterCallback.agent_Release(); + } + + agent_org_bluez_agent1_complete_release(object, invocation); + + g_dbus_interface_skeleton_unexport( + G_DBUS_INTERFACE_SKELETON(agnet_interface)); + + g_object_unref(agnet_interface); + agent_registered = FALSE; + +#ifdef AGENT_THREAD + if(agentLoop){ + g_main_loop_quit(agentLoop); + } +#endif + + return TRUE; +} + +/* + * agent api + * Methods : string RequestPinCode(object device) + * + * This method gets called when the service daemon + * needs to get the passkey for an authentication. + * + * The return value should be a string of 1-16 characters + * length. The string can be alphanumeric. + */ +static gboolean +on_handle_RequestPinCode (AGENTOrgBluezAgent1 *object, + GDBusMethodInvocation *invocation, + const gchar *device, + gpointer user_data) +{ + + LOGD("device:%s.\n",device); + + gboolean ret = FALSE; + const gchar *error = ERROR_BLUEZ_REJECT; + gchar *response; + + if (NULL != agent_RegisterCallback.agent_RequestPinCode) + { + ret = agent_RegisterCallback.agent_RequestPinCode (device, + &response, &error); + } + + if (TRUE == ret) + { + agent_org_bluez_agent1_complete_request_pin_code(object, + invocation, response); + g_free(response); + + } + else + { + g_dbus_method_invocation_return_dbus_error (invocation, error, ""); + } + + return TRUE; +} + +/* + * agent api + * Methods : void DisplayPinCode(object device, string pincode) + * + * This method gets called when the service daemon + * needs to display a pincode for an authentication. + */ +static gboolean +on_handle_DisplayPinCode (AGENTOrgBluezAgent1 *object, + GDBusMethodInvocation *invocation, + const gchar *device, + const gchar *pincode, + gpointer user_data) +{ + + LOGD("device:%s,pincode:%s.\n",device, pincode); + + gboolean ret = FALSE; + const gchar *error = ERROR_BLUEZ_REJECT; + + if (NULL != agent_RegisterCallback.agent_DisplayPinCode) + { + ret = agent_RegisterCallback.agent_DisplayPinCode(device, + pincode, &error); + } + + if (TRUE == ret) + { + agent_org_bluez_agent1_complete_display_pin_code(object, invocation); + } + else + { + g_dbus_method_invocation_return_dbus_error (invocation, error, ""); + } + + return TRUE; +} + + +/* + * agent api + * Methods : uint32 RequestPasskey(object device) + * + * This method gets called when the service daemon + * needs to get the passkey for an authentication. + * + * The return value should be a numeric value + * between 0-999999. + */ +static gboolean +on_handle_RequestPasskey (AGENTOrgBluezAgent1 *object, + GDBusMethodInvocation *invocation, + const gchar *device, + gpointer user_data) +{ + + LOGD("device:%s.\n",device); + + gboolean ret = FALSE; + const gchar *error = ERROR_BLUEZ_REJECT; + guint passkey; + + if (NULL != agent_RegisterCallback.agent_RequestPasskey) + { + ret = agent_RegisterCallback.agent_RequestPasskey(device, + &passkey, &error); + } + + if (TRUE == ret) + { + agent_org_bluez_agent1_complete_request_passkey(object, + invocation, passkey); + } + else + { + g_dbus_method_invocation_return_dbus_error (invocation, error, ""); + } + + return TRUE; + +} + + +/* + * agent api + * Methods : void DisplayPasskey(object device, uint32 passkey, uint16 entered) + * + * This method gets called when the service daemon + * needs to display a passkey for an authentication. + * + * The entered parameter indicates the number of already + * typed keys on the remote side. + */ +static gboolean +on_handle_DisplayPasskey (AGENTOrgBluezAgent1 *object, + GDBusMethodInvocation *invocation, + const gchar *device, + guint passkey, + guint16 entered, + gpointer user_data) +{ + + LOGD("device:%s,passkey:%d,entered:%d.\n",device, passkey, entered); + + //gboolean ret = FALSE; + + if (NULL != agent_RegisterCallback.agent_DisplayPasskey) + { + agent_RegisterCallback.agent_DisplayPasskey(device, passkey, entered); + } + + agent_org_bluez_agent1_complete_display_passkey(object, invocation); + + + return TRUE; + +} + +/* + * agent api + * Methods : void RequestConfirmation(object device, uint32 passkey) + * + * This method gets called when the service daemon + * needs to confirm a passkey for an authentication. + * + * To confirm the value it should return an empty reply + * or an error in case the passkey is invalid. + */ +static gboolean +on_handle_RequestConfirmation (AGENTOrgBluezAgent1 *object, + GDBusMethodInvocation *invocation, + const gchar *device, + guint passkey, + gpointer user_data) +{ + LOGD("device:%s,passkey:%d.\n", device, passkey); + + gboolean ret = FALSE; + const gchar *error = ERROR_BLUEZ_REJECT; + + if (NULL != agent_RegisterCallback.agent_RequestConfirmation) + { + ret = agent_RegisterCallback.agent_RequestConfirmation(device, + passkey, &error); + } + LOGD("ret %d\n",ret); + if (TRUE == ret) + { + agent_event_new(object, invocation,REQUEST_CONFIRMATION); + //agent_org_bluez_agent1_complete_request_confirmation(object, + // invocation); + } + else + { + g_dbus_method_invocation_return_dbus_error (invocation, error, ""); + } + + return TRUE; +} + +/* + * agent api + * Methods : void RequestAuthorization(object device) + * + * This method gets called to request the user to + * authorize an incoming pairing attempt which + * would in other circumstances trigger the just-works + * model. + */ +static gboolean +on_handle_RequestAuthorization (AGENTOrgBluezAgent1 *object, + GDBusMethodInvocation *invocation, + const gchar *device, + gpointer user_data) +{ + LOGD("device:%s.\n",device); + + gboolean ret = FALSE; + const gchar *error = ERROR_BLUEZ_REJECT; + + if (NULL != agent_RegisterCallback.agent_RequestAuthorization) + { + ret = agent_RegisterCallback.agent_RequestAuthorization(device,&error); + } + + if (TRUE == ret) + { + agent_org_bluez_agent1_complete_request_authorization(object, + invocation); + } + else + { + g_dbus_method_invocation_return_dbus_error (invocation, error, ""); + } + + return TRUE; +} + +/* + * agent api + * Methods : void AuthorizeService(object device, string uuid) + * + * This method gets called when the service daemon + * needs to authorize a connection/service request. + */ +static gboolean +on_handle_AuthorizeService (AGENTOrgBluezAgent1 *object, + GDBusMethodInvocation *invocation, + const gchar *device, + const gchar *uuid, + gpointer user_data) +{ + + LOGD("device:%s.uuid:%s\n",device,uuid); + + gboolean ret = FALSE; + const gchar *error = ERROR_BLUEZ_REJECT; + + if (NULL != agent_RegisterCallback.agent_AuthorizeService) + { + ret = agent_RegisterCallback.agent_AuthorizeService(device, + uuid, &error); + } + + if (TRUE == ret) + { + agent_org_bluez_agent1_complete_authorize_service(object, invocation); + } + else + { + g_dbus_method_invocation_return_dbus_error (invocation, error, ""); + } + + return TRUE; +} + +/* + * agent api + * Methods : void Cancel() + * + * This method gets called to indicate that the agent + * request failed before a reply was returned. + */ +static gboolean +on_handle_Cancel (AGENTOrgBluezAgent1 *object, + GDBusMethodInvocation *invocation, + gpointer user_data) +{ + LOGD("\n"); + + if (NULL != agent_RegisterCallback.agent_Cancel) + { + agent_RegisterCallback.agent_Cancel(); + } + + agent_org_bluez_agent1_complete_cancel(object, invocation); + + return TRUE; + +} + +/* + * agent init + * init the dbus and register the agent to bluez + */ +static int create_and_register_agent(const char *capability) +{ + GError *error = NULL; + gboolean ret; + GVariant *value; + + LOGD("%s\n",capability); + + if (agent_registered == TRUE) { + LOGD("Agent is already registered\n"); + return -1; + } + + system_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error); + + if (error) + { + LOGE("errr:%s",error->message); + g_error_free(error); + + return -1; + } + + agent_capability = capability; + + agnet_interface = agent_org_bluez_agent1_skeleton_new (); + + g_signal_connect (agnet_interface, + "handle-release", + G_CALLBACK (on_handle_Release), + NULL); + + g_signal_connect (agnet_interface, + "handle-request-pin-code", + G_CALLBACK (on_handle_RequestPinCode), + NULL); + + g_signal_connect (agnet_interface, + "handle-display-pin-code", + G_CALLBACK (on_handle_DisplayPinCode), + NULL); + + g_signal_connect (agnet_interface, + "handle-request-passkey", + G_CALLBACK (on_handle_RequestPasskey), + NULL); + + g_signal_connect (agnet_interface, + "handle-display-passkey", + G_CALLBACK (on_handle_DisplayPasskey), + NULL); + + g_signal_connect (agnet_interface, + "handle-request-confirmation", + G_CALLBACK (on_handle_RequestConfirmation), + NULL); + + g_signal_connect (agnet_interface, + "handle-request-authorization", + G_CALLBACK (on_handle_RequestAuthorization), + NULL); + + g_signal_connect (agnet_interface, + "handle-authorize-service", + G_CALLBACK (on_handle_AuthorizeService), + NULL); + + g_signal_connect (agnet_interface, + "handle-cancel", + G_CALLBACK (on_handle_Cancel), + NULL); + + ret = g_dbus_interface_skeleton_export ( + G_DBUS_INTERFACE_SKELETON (agnet_interface), + system_conn, + AGENT_PATH, + &error); + + if (FALSE == ret) + { + LOGE("errr:%s",error->message); + g_error_free(error); + g_object_unref(system_conn); + + return -1; + } + + value = g_dbus_connection_call_sync(system_conn, BLUEZ_SERVICE, + AGENT_PATH, AGENT_MANAGER_INTERFACE, + "RegisterAgent", g_variant_new("(os)", AGENT_PATH, + agent_capability), + NULL, G_DBUS_CALL_FLAGS_NONE, DBUS_REPLY_TIMEOUT, + NULL, &error); + + if (NULL == value) { + LOGE ("RegisterAgent Err: %s", error->message); + g_error_free(error); + + g_dbus_interface_skeleton_unexport( + G_DBUS_INTERFACE_SKELETON(agnet_interface)); + + g_object_unref(system_conn); + return -1; + } + + g_variant_unref(value); + + agent_capability = NULL; + + agent_registered = TRUE; + + return 0; +} + +#ifdef AGENT_THREAD +/* + * agent thread function + */ +static void *agent_event_loop_thread(const char *capability) +{ + + agentLoop = g_main_loop_new(NULL, FALSE); + guint id; + GError *error = NULL; + gboolean ret; + + ret = create_and_register_agent(capability); + + if (0 == ret) + { + LOGD("g_main_loop_run\n"); + g_main_loop_run(agentLoop); + + + } + + g_main_loop_unref(agentLoop); + agentLoop = NULL; + LOGD("exit...\n"); +} +#endif + + +/* --- PUBLIC FUNCTIONS --- */ + + +/* + * start agent. + * Returns: 0 - success or other errors + */ +int agent_register(const char *capability) +{ + int ret = 0; + LOGD("\n"); + + if (agent_registered == TRUE) { + LOGD("Agent is already registered\n"); + return -1; + } + +#ifdef AGENT_THREAD + pthread_t thread_id; + pthread_create(&thread_id, NULL, agent_event_loop_thread, capability); + pthread_setname_np(thread_id, "agent"); + +#else + ret = create_and_register_agent(capability); +#endif + + return ret; +} + +/* + * stop agent. + * Returns: 0 - success or other errors + */ +int stop_agent() +{ + GError *error = NULL; + GVariant *value; + + LOGD("\n"); + + if (agent_registered == FALSE) { + LOGD("No agent is registered\n"); + return -1; + } + + value = g_dbus_connection_call_sync(system_conn, BLUEZ_SERVICE, + AGENT_PATH, AGENT_MANAGER_INTERFACE, + "UnregisterAgent", g_variant_new("(o)", AGENT_PATH ), + NULL, G_DBUS_CALL_FLAGS_NONE, DBUS_REPLY_TIMEOUT, + NULL, &error); + + if (NULL == value) { + LOGE ("Error UnregisterAgent: %s", error->message); + g_error_free(error); + + return -1; + } + + g_dbus_interface_skeleton_unexport( + G_DBUS_INTERFACE_SKELETON(agnet_interface)); + + g_object_unref(agnet_interface); + + g_object_unref(system_conn); + + agent_registered = FALSE; + + memset(&agent_RegisterCallback, 0, sizeof(Agent_RegisterCallback_t)); + +#ifdef AGENT_THREAD + if(agentLoop){ + g_main_loop_quit(agentLoop); + } +#endif + + return 0; +} + +/* + * Register Agent Callback function + */ +void agent_API_register(const Agent_RegisterCallback_t* pstRegisterCallback) +{ + LOGD("\n"); + + if (NULL != pstRegisterCallback) + { + if (NULL != pstRegisterCallback->agent_Release) + { + agent_RegisterCallback.agent_Release = + pstRegisterCallback->agent_Release; + } + + if (NULL != pstRegisterCallback->agent_RequestPinCode) + { + agent_RegisterCallback.agent_RequestPinCode = + pstRegisterCallback->agent_RequestPinCode; + } + + if (NULL != pstRegisterCallback->agent_DisplayPinCode) + { + agent_RegisterCallback.agent_DisplayPinCode = + pstRegisterCallback->agent_DisplayPinCode; + } + + if (NULL != pstRegisterCallback->agent_RequestPasskey) + { + agent_RegisterCallback.agent_RequestPasskey = + pstRegisterCallback->agent_RequestPasskey; + } + + if (NULL != pstRegisterCallback->agent_DisplayPasskey) + { + agent_RegisterCallback.agent_DisplayPasskey = + pstRegisterCallback->agent_DisplayPasskey; + } + + if (NULL != pstRegisterCallback->agent_RequestConfirmation) + { + agent_RegisterCallback.agent_RequestConfirmation = + pstRegisterCallback->agent_RequestConfirmation; + } + + if (NULL != pstRegisterCallback->agent_RequestAuthorization) + { + agent_RegisterCallback.agent_RequestAuthorization = + pstRegisterCallback->agent_RequestAuthorization; + } + + if (NULL != pstRegisterCallback->agent_AuthorizeService) + { + agent_RegisterCallback.agent_AuthorizeService = + pstRegisterCallback->agent_AuthorizeService; + } + + if (NULL != pstRegisterCallback->agent_Cancel) + { + agent_RegisterCallback.agent_Cancel = + pstRegisterCallback->agent_Cancel; + } + + } + +} + +/* + * Send the agent event "RequestConfirmation" reply + */ +int agent_send_confirmation(gboolean confirmation) +{ + if (NULL == agent_event) + { + LOGW("Not agent event"); + return -1; + } + LOGD("%d-%d\n", confirmation, agent_event->type); + + if (REQUEST_CONFIRMATION != agent_event->type) + { + return -1; + } + + if (TRUE == confirmation){ + agent_org_bluez_agent1_complete_request_confirmation(agent_event->object, + agent_event->invocation); + }else{ + g_dbus_method_invocation_return_dbus_error (agent_event->invocation, + ERROR_BLUEZ_REJECT, ""); + } + + g_free(agent_event); + agent_event = NULL; + return 0; +} +/****************************** The End Of File ******************************/ + |