📄 agent.c
字号:
/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2008 Nokia Corporation * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org> * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */#ifdef HAVE_CONFIG_H#include <config.h>#endif#include <stdio.h>#include <errno.h>#include <stdlib.h>#include <sys/socket.h>#include <sys/ioctl.h>#include <bluetooth/bluetooth.h>#include <bluetooth/hci.h>#include <bluetooth/hci_lib.h>#include <bluetooth/sdp.h>#include <glib.h>#include <dbus/dbus.h>#include <gdbus.h>#include "hcid.h"#include "dbus-common.h"#include "error.h"#include "adapter.h"#include "dbus-hci.h"#include "device.h"#include "agent.h"#define REQUEST_TIMEOUT (60 * 1000) /* 60 seconds */#define AGENT_TIMEOUT (10 * 60 * 1000) /* 10 minutes */typedef enum { AGENT_REQUEST_PASSKEY, AGENT_REQUEST_CONFIRMATION, AGENT_REQUEST_PINCODE, AGENT_REQUEST_AUTHORIZE, AGENT_REQUEST_CONFIRM_MODE} agent_request_type_t;struct agent { struct adapter *adapter; char *name; char *path; uint8_t capability; struct agent_request *request; int exited; agent_remove_cb remove_cb; void *remove_cb_data; guint listener_id;};struct agent_request { agent_request_type_t type; struct agent *agent; DBusMessage *msg; DBusPendingCall *call; void *cb; void *user_data;};static DBusConnection *connection = NULL;static int request_fallback(struct agent_request *req, DBusPendingCallNotifyFunction function);static void agent_release(struct agent *agent){ DBusMessage *message; debug("Releasing agent %s, %s", agent->name, agent->path); if (agent->request) agent_cancel(agent); message = dbus_message_new_method_call(agent->name, agent->path, "org.bluez.Agent", "Release"); if (message == NULL) { error("Couldn't allocate D-Bus message"); return; } dbus_message_set_no_reply(message, TRUE); dbus_connection_send(connection, message, NULL); dbus_message_unref(message);}static int send_cancel_request(struct agent_request *req){ DBusMessage *message; message = dbus_message_new_method_call(req->agent->name, req->agent->path, "org.bluez.Agent", "Cancel"); if (message == NULL) { error("Couldn't allocate D-Bus message"); return -ENOMEM; } dbus_message_set_no_reply(message, TRUE); dbus_connection_send(connection, message, NULL); dbus_message_unref(message); return 0;}static void agent_request_free(struct agent_request *req){ if (req->msg) dbus_message_unref(req->msg); if (req->call) dbus_pending_call_unref(req->call); if (req->agent && req->agent->request) req->agent->request = NULL; g_free(req);}static void agent_exited(void *user_data){ struct agent *agent = user_data; debug("Agent exited without calling Unregister"); agent_destroy(agent, TRUE);}static void agent_free(struct agent *agent){ if (!agent) return; if (agent->remove_cb) agent->remove_cb(agent, agent->remove_cb_data); if (agent->request) { DBusError err; agent_pincode_cb pincode_cb; agent_cb cb; dbus_error_init(&err); dbus_set_error_const(&err, "org.bluez.Error.Failed", "Canceled"); switch (agent->request->type) { case AGENT_REQUEST_PINCODE: pincode_cb = agent->request->cb; pincode_cb(agent, &err, NULL, agent->request->user_data); break; default: cb = agent->request->cb; cb(agent, &err, agent->request->user_data); } dbus_error_free(&err); agent_cancel(agent); } if (!agent->exited) { g_dbus_remove_watch(connection, agent->listener_id); agent_release(agent); } g_free(agent->name); g_free(agent->path); g_free(agent);}struct agent *agent_create(struct adapter *adapter, const char *name, const char *path, uint8_t capability, agent_remove_cb cb, void *remove_cb_data){ struct agent *agent; if (adapter->agent && g_str_equal(adapter->agent->name, name)) return NULL; agent = g_new0(struct agent, 1); agent->adapter = adapter; agent->name = g_strdup(name); agent->path = g_strdup(path); agent->capability = capability; agent->remove_cb = cb; agent->remove_cb_data = remove_cb_data; agent->listener_id = g_dbus_add_disconnect_watch(connection, name, agent_exited, agent, NULL); return agent;}int agent_destroy(struct agent *agent, gboolean exited){ agent->exited = exited; agent_free(agent); return 0;}static struct agent_request *agent_request_new(struct agent *agent, agent_request_type_t type, void *cb, void *user_data){ struct agent_request *req; req = g_new0(struct agent_request, 1); req->agent = agent; req->type = type; req->cb = cb; req->user_data = user_data; return req;}int agent_cancel(struct agent *agent){ if (!agent->request) return -EINVAL; if (agent->request->call) dbus_pending_call_cancel(agent->request->call); if (!agent->exited) send_cancel_request(agent->request); agent_request_free(agent->request); agent->request = NULL; return 0;}static void simple_agent_reply(DBusPendingCall *call, void *user_data){ struct agent_request *req = user_data; struct agent *agent = req->agent; DBusMessage *message; DBusError err; agent_cb cb = req->cb; /* steal_reply will always return non-NULL since the callback * is only called after a reply has been received */ message = dbus_pending_call_steal_reply(call); dbus_error_init(&err); if (dbus_set_error_from_message(&err, message)) { if ((g_str_equal(DBUS_ERROR_UNKNOWN_METHOD, err.name) || g_str_equal(DBUS_ERROR_NO_REPLY, err.name)) && request_fallback(req, simple_agent_reply) == 0) { dbus_error_free(&err); return; } error("Agent replied with an error: %s, %s", err.name, err.message); cb(agent, &err, req->user_data); dbus_error_free(&err); goto done; } dbus_error_init(&err); if (!dbus_message_get_args(message, &err, DBUS_TYPE_INVALID)) { error("Wrong reply signature: %s", err.message); cb(agent, &err, req->user_data); dbus_error_free(&err); goto done; } cb(agent, NULL, req->user_data);done: dbus_message_unref(message); agent->request = NULL; agent_request_free(req);}static int agent_call_authorize(struct agent_request *req, const char *device_path, const char *uuid){ struct agent *agent = req->agent; req->msg = dbus_message_new_method_call(agent->name, agent->path, "org.bluez.Agent", "Authorize"); if (!req->msg) { error("Couldn't allocate D-Bus message"); return -ENOMEM; } dbus_message_append_args(req->msg, DBUS_TYPE_OBJECT_PATH, &device_path, DBUS_TYPE_STRING, &uuid, DBUS_TYPE_INVALID); if (dbus_connection_send_with_reply(connection, req->msg, &req->call, REQUEST_TIMEOUT) == FALSE) { error("D-Bus send failed"); return -EIO; } dbus_pending_call_set_notify(req->call, simple_agent_reply, req, NULL); return 0;}int agent_authorize(struct agent *agent, const char *path, const char *uuid, agent_cb cb, void *user_data){ struct agent_request *req; int err; if (agent->request) return -EBUSY; req = agent_request_new(agent, AGENT_REQUEST_AUTHORIZE, cb, user_data); err = agent_call_authorize(req, path, uuid); if (err < 0) { agent_request_free(req); return DBUS_HANDLER_RESULT_NEED_MEMORY; } agent->request = req; debug("authorize request was sent for %s", path); return 0;}static void pincode_reply(DBusPendingCall *call, void *user_data){ struct agent_request *req = user_data; struct agent *agent = req->agent; struct adapter *adapter = agent->adapter; agent_pincode_cb cb = req->cb; DBusMessage *message; DBusError err; bdaddr_t sba; size_t len; char *pin; const gchar *source = adapter_get_address(adapter); /* steal_reply will always return non-NULL since the callback * is only called after a reply has been received */ message = dbus_pending_call_steal_reply(call); dbus_error_init(&err); if (dbus_set_error_from_message(&err, message)) { if ((g_str_equal(DBUS_ERROR_UNKNOWN_METHOD, err.name) || g_str_equal(DBUS_ERROR_NO_REPLY, err.name)) && request_fallback(req, pincode_reply) == 0) { dbus_error_free(&err); return; } error("Agent replied with an error: %s, %s", err.name, err.message); cb(agent, &err, NULL, req->user_data); dbus_error_free(&err); goto done;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -