15 #define BLUEZ_PREFIX "org.bluez"
17 #define BLUEZ_SERVICE BLUEZ_PREFIX
18 #define BLUEZ_MANAGER_IFACE BLUEZ_PREFIX ".Manager"
19 #define BLUEZ_ADAPTER_IFACE BLUEZ_PREFIX ".Adapter"
20 #define BLUEZ_DEVICE_IFACE BLUEZ_PREFIX ".Device"
21 #define BLUEZ_AGENT_IFACE BLUEZ_PREFIX ".Agent"
23 #define AGENT_PATH "/org/bluez/agent_poc"
24 #define AGENT_CAPABILITIES "KeyboardDisplay"
26 #define AGENT_PASSKEY 123456
27 #define AGENT_PINCODE "123456"
29 #define AGENT_INTERFACE_XML \
31 " <interface name='org.bluez.Agent'>" \
32 " <method name='Release'>" \
34 " <method name='Authorize'>" \
35 " <arg type='o' name='device' direction='in'/>" \
36 " <arg type='s' name='uuid' direction='in'/>" \
38 " <method name='RequestPinCode'>" \
39 " <arg type='o' name='device' direction='in'/>" \
40 " <arg type='s' name='pincode' direction='out'/>" \
42 " <method name='RequestPasskey'>" \
43 " <arg type='o' name='device' direction='in'/>" \
44 " <arg type='u' name='passkey' direction='out'/>" \
46 " <method name='DisplayPasskey'>" \
47 " <arg type='o' name='device' direction='in'/>" \
48 " <arg type='u' name='passkey' direction='in'/>" \
50 " <method name='DisplayPinCode'>" \
51 " <arg type='o' name='device' direction='in'/>" \
52 " <arg type='s' name='pincode' direction='in'/>" \
54 " <method name='RequestConfirmation'>" \
55 " <arg type='o' name='device' direction='in'/>" \
56 " <arg type='u' name='passkey' direction='in'/>" \
58 " <method name='ConfirmModeChange'>" \
59 " <arg type='s' name='mode' direction='in'/>" \
61 " <method name='Cancel'>" \
67 * "Release" ... does nothing
68 * "Authorize" ... automatically authorized
69 * "RequestPinCode" ... used default pin code (AGENT_PINCODE)
70 * "RequestPasskey" ... used default passkey (AGENT_PASSKEY)
71 * "RequestConfirmation" ... automatically confirmed
72 * "DisplayPinCode" ... does nothing
73 * "DisplayPasskey" ... does nothing
74 * "ConfirmModeChange" ... automatically confirmed
75 * "Cancel" ... does nothing
80 mAgentRegistrationId(-1),
81 mAgentIntrospectionData(NULL)
85 mAdapterPath = getDefaultAdapter();
87 LoggerE("Unable to get default adapter");
89 memset(&mAgentIfaceVTable, 0, sizeof(mAgentIfaceVTable));
91 // subscribe for AdapterAdded/AdapterRemoved to get notification about the change
92 Utils::setSignalListener(G_BUS_TYPE_SYSTEM, BLUEZ_SERVICE, BLUEZ_MANAGER_IFACE,
93 "/", "AdapterAdded", Bluez::handleSignal,
95 Utils::setSignalListener(G_BUS_TYPE_SYSTEM, BLUEZ_SERVICE, BLUEZ_MANAGER_IFACE,
96 "/", "AdapterRemoved", Bluez::handleSignal,
100 Utils::setSignalListener(G_BUS_TYPE_SYSTEM, BLUEZ_SERVICE, BLUEZ_ADAPTER_IFACE,
101 mAdapterPath, "DeviceCreated", Bluez::handleSignal,
103 Utils::setSignalListener(G_BUS_TYPE_SYSTEM, BLUEZ_SERVICE, BLUEZ_ADAPTER_IFACE,
104 mAdapterPath, "DeviceRemoved", Bluez::handleSignal,
106 Utils::setSignalListener(G_BUS_TYPE_SYSTEM, BLUEZ_SERVICE, BLUEZ_ADAPTER_IFACE,
107 mAdapterPath, "PropertyChanged", Bluez::handleSignal,
119 gchar* Bluez::getDefaultAdapter()
122 GVariant *reply = NULL;
123 reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
130 G_DBUS_CALL_FLAGS_NONE,
136 LoggerE("Failed to get default adapter: " << err->message);
140 LoggerE("Reply from 'DefaultAdapter' is null");
144 char *adapter = NULL;
145 g_variant_get(reply, "(o)", &adapter);
146 LoggerD("DefaultAdapter: " << adapter);
148 // make a copy of adapter, 'cause it will be destroyed when 'reply' is un-refed
149 char *result = adapter?strdup(adapter):NULL;
151 g_variant_unref(reply);
156 bool Bluez::setAdapterPowered(bool value) {
159 g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL,NULL),
164 g_variant_new ("(sv)", // floating parameters are consumed, no cleanup/unref needed
166 g_variant_new("b", &value) // floating parameters are consumed, no cleanup/unref needed
169 G_DBUS_CALL_FLAGS_NONE,
175 LoggerE("Failed to call \"SetProperty\" DBUS method: " << err->message);
186 void Bluez::handleSignal(GDBusConnection *connection,
188 const gchar *object_path,
189 const gchar *interface_name,
190 const gchar *signal_name,
191 GVariant *parameters,
194 LoggerD("signal received: '" << interface_name << "' -> '" << signal_name << "' -> '" << object_path << "'");
196 Bluez *ctx = static_cast<Bluez*>(user_data);
198 LoggerD("Failed to cast to Bluez");
202 if(!strcmp(interface_name, BLUEZ_MANAGER_IFACE)) {
203 if(!strcmp(signal_name, "AdapterAdded")) {
204 const char *adapter = NULL;
205 g_variant_get(parameters, "(o)", &adapter);
207 LoggerD("Adapter added: " << adapter);
208 if(!ctx->mAdapterPath) {
209 // make added adapter as default
210 ctx->mAdapterPath = strdup(adapter);
212 ctx->registerAgent();
213 ctx->defaultAdapterAdded();
217 else if(!strcmp(signal_name, "AdapterRemoved")) {
218 const char *adapter = NULL;
219 g_variant_get(parameters, "(o)", &adapter);
221 LoggerD("Adapter removed: " << adapter);
222 if(ctx->mAdapterPath && !strcmp(ctx->mAdapterPath, adapter)) {
223 // removed the default adapter
224 free(ctx->mAdapterPath);
225 ctx->mAdapterPath = NULL;
226 ctx->defaultAdapterRemoved();
231 else if(!strcmp(interface_name, BLUEZ_ADAPTER_IFACE)) {
232 if(!strcmp(signal_name, "DeviceCreated")) {
234 g_variant_get(parameters, "(o)", &device);
235 LoggerD("DeviceCreated: " << (device?device:"UNKNOWN"));
237 // subscribe for PropertyChanged signal on the device,
238 // to get notification about device being paired
239 Utils::setSignalListener(G_BUS_TYPE_SYSTEM, BLUEZ_SERVICE, BLUEZ_DEVICE_IFACE,
240 device, "PropertyChanged", Bluez::handleSignal,
244 else if(!strcmp(signal_name, "DeviceRemoved")) {
246 g_variant_get(parameters, "(o)", &device);
247 LoggerD("DeviceRemoved: " << (device?device:"UNKNOWN"));
248 ctx->deviceRemoved(device);
250 else if(!strcmp(signal_name, "PropertyChanged")) {
253 g_variant_get(parameters, "(sv)", &name, &v_value);
254 LoggerD("\tname=" << name);
255 if(!strcmp(name, "Powered")) {
256 bool value = g_variant_get_boolean(v_value);
257 ctx->adapterPowered(value);
258 //LoggerD("\tvalue=" << (value?"TRUE":"FALSE"));
262 else if(!strcmp(interface_name, BLUEZ_DEVICE_IFACE)) {
263 if(!strcmp(signal_name, "PropertyChanged")) {
266 g_variant_get(parameters, "(sv)", &name, &value);
267 if(!strcmp(name, "Paired")) {
268 bool paired = g_variant_get_boolean(value);
269 if(paired) { // the device has been paired
270 ctx->deviceCreated(object_path);
277 void Bluez::agentHandleMethodCall( GDBusConnection *connection,
279 const gchar *object_path,
280 const gchar *interface_name,
281 const gchar *method_name,
282 GVariant *parameters,
283 GDBusMethodInvocation *invocation,
286 LoggerD("entered\n\tsender=" << sender << "\n\tobject_path=" << object_path << "\n\tinterface_name=" << interface_name << "\n\tmethod_name=" << method_name);
288 Bluez *ctx = static_cast<Bluez*>(user_data);
290 LoggerD("Failed to cast to Bluez");
291 g_dbus_method_invocation_return_value(invocation, NULL);
295 if(!strcmp(method_name, "Authorize")) {
296 g_dbus_method_invocation_return_value(invocation, NULL);
298 else if(!strcmp(method_name, "RequestPinCode")) {
299 g_dbus_method_invocation_return_value(invocation, g_variant_new("(s)", AGENT_PINCODE));
301 else if(!strcmp(method_name, "RequestPasskey")) {
302 g_dbus_method_invocation_return_value(invocation, g_variant_new("(u)", AGENT_PASSKEY));
304 else if (!strcmp(method_name, "Release")) {
305 if(!strcmp(object_path, AGENT_PATH)) { // released agent for pairing
306 bool unregistered = g_dbus_connection_unregister_object(g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL), ctx->mAgentRegistrationId);
308 ctx->mAgentRegistrationId = -1;
310 g_dbus_method_invocation_return_value(invocation, NULL);
313 // DisplayPasskey, DisplayPinCode, RequestConfirmation, ConfirmModeChange, Cancel
314 g_dbus_method_invocation_return_value(invocation, NULL);
318 bool Bluez::isDevicePaired(const char *bt_addr) {
325 GVariant *reply = NULL;
326 reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
331 g_variant_new("(s)", bt_addr),
333 G_DBUS_CALL_FLAGS_NONE,
344 const char *tmp = NULL;
345 g_variant_get(reply, "(o)", &tmp);
347 g_variant_unref(reply);
351 char *device = strdup(tmp);
352 g_variant_unref(reply);
354 // get device properties and check if the device is Paired
355 reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
362 G_DBUS_CALL_FLAGS_NONE,
374 g_variant_get(reply, "(a{sv})", &iter);
377 while(g_variant_iter_next(iter, "{sv}", &key, &value)) {
378 if(!strcmp(key, "Paired")) {
379 paired = g_variant_get_boolean(value);
385 g_variant_unref(reply);
390 void Bluez::setupAgent()
392 LoggerD("entered: registering agent " << AGENT_PATH);
395 if(mAgentRegistrationId > 0) { // alread registered
396 LoggerD("Bluez agent registered");
401 mAgentIfaceVTable.method_call = Bluez::agentHandleMethodCall;
402 mAgentIntrospectionData = g_dbus_node_info_new_for_xml(AGENT_INTERFACE_XML, NULL);
404 if (mAgentIntrospectionData == NULL) {
405 LoggerD("failed to create introspection data.");
408 LoggerD("introspection data parsed OK");
411 mAgentRegistrationId = g_dbus_connection_register_object( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
413 mAgentIntrospectionData->interfaces[0],
414 &mAgentIfaceVTable, //const GDBusInterfaceVTable *vtable,
416 NULL, //GDestroyNotify
420 LoggerD("Failed to register object: " << AGENT_PATH << " : " << err->message);
424 LoggerD("object registered with id=" << mAgentRegistrationId);
427 void Bluez::registerAgent()
432 g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
437 g_variant_new("(os)", AGENT_PATH, AGENT_CAPABILITIES), // floating variants are consumed
439 G_DBUS_CALL_FLAGS_NONE,
444 LoggerE("Failed to register agent: " << err->message);
449 LoggerD("Agent registered");