summaryrefslogtreecommitdiffstats
path: root/bluetooth-agent.c
diff options
context:
space:
mode:
Diffstat (limited to 'bluetooth-agent.c')
-rw-r--r--bluetooth-agent.c736
1 files changed, 736 insertions, 0 deletions
diff --git a/bluetooth-agent.c b/bluetooth-agent.c
new file mode 100644
index 0000000..7193ce5
--- /dev/null
+++ b/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 ******************************/
+