aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Nettle <nettle.paul@gmail.com>2017-09-03 08:15:12 -0500
committerPaul Nettle <nettle.paul@gmail.com>2017-09-03 08:15:12 -0500
commit23e46d2de44a3d49063e852a38b020e7407a78bc (patch)
tree7eca15bc1e93dc47d828dc9cef72f66515d287c5
parentCleaned up the logging a bit, improved server termination status returned fro... (diff)
downloadgobbledegook-23e46d2de44a3d49063e852a38b020e7407a78bc.tar.gz
gobbledegook-23e46d2de44a3d49063e852a38b020e7407a78bc.tar.bz2
gobbledegook-23e46d2de44a3d49063e852a38b020e7407a78bc.zip
The GGK server names are no longer in Globals.h but are now configured by ggkStart() allowing an application to change them based on configuration rather than compilation. Power-off-disconnect errors hacked out of existence. A few log lines that were set to trace converted to debug log levels to reduce logspam.
-rw-r--r--README.md25
-rw-r--r--include/Gobbledegook.h36
-rw-r--r--src/DBusInterface.h2
-rw-r--r--src/DBusMethod.h3
-rw-r--r--src/DBusObject.cpp2
-rw-r--r--src/DBusObject.h2
-rw-r--r--src/GattCharacteristic.cpp2
-rw-r--r--src/GattDescriptor.cpp2
-rw-r--r--src/Globals.h32
-rw-r--r--src/Gobbledegook.cpp39
-rw-r--r--src/HciAdapter.cpp15
-rw-r--r--src/Init.cpp67
-rw-r--r--src/Mgmt.cpp29
-rw-r--r--src/Mgmt.h8
-rw-r--r--src/Server.cpp47
-rw-r--r--src/Server.h103
-rw-r--r--src/Utils.cpp2
-rw-r--r--src/standalone.cpp8
18 files changed, 318 insertions, 106 deletions
diff --git a/README.md b/README.md
index 634dac2..75d8491 100644
--- a/README.md
+++ b/README.md
@@ -329,6 +329,31 @@ Once you've done this, run the following commands to reload these settings and r
sudo service bluetooth stop
sudo service bluetooth start
+### Enabling D-Bus Permissions
+
+In order for our application to communicate over D-Bus, we'll need to ask D-Bus for an *owned name*, which will in effect be our address on D-Bus. D-Bus must be configured to grant us permissions to do this. We'll grant these permissions to user `root`.
+
+You'll need to locate the D-Bus permissions on your box. Likely, you'll find a set of files for this in the directory `/etc/dbus-1/system.d`. Create the file `/etc/dbus-1/system.d/gobbledegook.conf` and give it the contents:
+
+ <!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+ <busconfig>
+ <policy user="root">
+ <allow own="com.gobbledegook"/>
+ <allow send_destination="com.gobbledegook"/>
+ <allow send_destination="org.bluez"/>
+ </policy>
+ <policy at_console="true">
+ <allow own="com.gobbledegook"/>
+ <allow send_destination="com.gobbledegook"/>
+ <allow send_destination="org.bluez"/>
+ </policy>
+ <policy context="default">
+ <deny send_destination="com.gobbledegook"/>
+ </policy>
+ </busconfig>
+
+Note the `com.gobbledegook` entries in your new `gobbledegook.conf` file. This must match the service name (the first parameter sent to `ggkStart()` in `standalone.cpp`). If you change the service name from `gobbledegook` to `clownface` in that call to `ggkStart()`, then you'll need to edit the `gobbledegook.conf` file and change all occurrances of `com.gobbledegook` to `com.clownface`.
+
### Enabling Bluetooth
You don't need to do anything. this server will automatically power on the adapter, enable LE with advertisement.
diff --git a/include/Gobbledegook.h b/include/Gobbledegook.h
index 6213c0f..1914490 100644
--- a/include/Gobbledegook.h
+++ b/include/Gobbledegook.h
@@ -187,7 +187,41 @@ extern "C"
//
// Similarly, the pointer to data returned to the data getter should point to non-volatile memory so that the server can use it
// safely for an indefinite period of time.
- int ggkStart(GGKServerDataGetter getter, GGKServerDataSetter setter, int maxAsyncInitTimeoutMS);
+ //
+ // serviceName: The name of our server (collectino of services)
+ //
+ // !!!IMPORTANT!!!
+ //
+ // This name must match tha name configured in the D-Bus permissions. See the Readme.md file for more information.
+ //
+ // This is used to build the path for our Bluetooth services. It also provides the base for the D-Bus owned name (see
+ // getOwnedName.)
+ //
+ // This value will be stored as lower-case only.
+ //
+ // Retrieve this value using the `TheServer->getName()` method
+ //
+ // advertisingName: The name for this controller, as advertised over LE
+ //
+ // IMPORTANT: Setting the advertisingName will change the system-wide name of the device. If that's not what you want, set
+ // BOTH advertisingName and advertisingShortName to as empty string ("") to prevent setting the advertising
+ // name.
+ //
+ // Retrieve this value using the `getAdvertisingName()` method
+ //
+ // advertisingShortName: The short name for this controller, as advertised over LE
+ //
+ // According to the spec, the short name is used in case the full name doesn't fit within Extended Inquiry Response (EIR) or
+ // Advertising Data (AD).
+ //
+ // IMPORTANT: Setting the advertisingName will change the system-wide name of the device. If that's not what you want, set
+ // BOTH advertisingName and advertisingShortName to as empty string ("") to prevent setting the advertising
+ // name.
+ //
+ // Retrieve this value using the `getAdvertisingShortName()` method
+ //
+ int ggkStart(const char *pServiceName, const char *pAdvertisingName, const char *pAdvertisingShortName,
+ GGKServerDataGetter getter, GGKServerDataSetter setter, int maxAsyncInitTimeoutMS);
// Blocks for up to maxAsyncInitTimeoutMS milliseconds until the server shuts down.
//
diff --git a/src/DBusInterface.h b/src/DBusInterface.h
index 1dc8971..858dc44 100644
--- a/src/DBusInterface.h
+++ b/src/DBusInterface.h
@@ -38,7 +38,6 @@
#include "TickEvent.h"
#include "DBusMethod.h"
-#include "DBusObjectPath.h"
namespace ggk {
@@ -49,6 +48,7 @@ namespace ggk {
struct DBusInterface;
struct GattProperty;
struct DBusObject;
+struct DBusObjectPath;
// ---------------------------------------------------------------------------------------------------------------------------------
// Useful Lambdas
diff --git a/src/DBusMethod.h b/src/DBusMethod.h
index e63b84b..f081f7b 100644
--- a/src/DBusMethod.h
+++ b/src/DBusMethod.h
@@ -45,6 +45,7 @@
#include "Globals.h"
#include "DBusObjectPath.h"
#include "Logger.h"
+#include "Server.h"
namespace ggk {
@@ -104,7 +105,7 @@ struct DBusMethod
return;
}
- Logger::trace(SSTR << "Calling method: [" << path << "]:[" << interfaceName << "]:[" << methodName << "]");
+ Logger::info(SSTR << "Calling method: [" << path << "]:[" << interfaceName << "]:[" << methodName << "]");
callback(*static_cast<const T *>(pOwner), pConnection, methodName, pParameters, pInvocation, pUserData);
}
diff --git a/src/DBusObject.cpp b/src/DBusObject.cpp
index 49d715a..0bfd2d3 100644
--- a/src/DBusObject.cpp
+++ b/src/DBusObject.cpp
@@ -238,7 +238,7 @@ std::string DBusObject::generateIntrospectionXML(int depth) const
}
xml += prefix + "<node name='" + getPathNode().toString() + "'>\n";
- xml += prefix + " <annotation name='" + kServerOwnedName + ".DBusObject.path' value='" + getPath().toString() + "' />\n";
+ xml += prefix + " <annotation name='" + TheServer->getServiceName() + ".DBusObject.path' value='" + getPath().toString() + "' />\n";
for (std::shared_ptr<const DBusInterface> interface : interfaces)
{
diff --git a/src/DBusObject.h b/src/DBusObject.h
index 79564ba..2d74e3c 100644
--- a/src/DBusObject.h
+++ b/src/DBusObject.h
@@ -37,7 +37,6 @@
#include <list>
#include <memory>
-#include "DBusInterface.h"
#include "DBusObjectPath.h"
namespace ggk {
@@ -45,6 +44,7 @@ namespace ggk {
struct GattProperty;
struct GattService;
struct GattUuid;
+struct DBusInterface;
struct DBusObject
{
diff --git a/src/GattCharacteristic.cpp b/src/GattCharacteristic.cpp
index 9bfafd9..a10c04d 100644
--- a/src/GattCharacteristic.cpp
+++ b/src/GattCharacteristic.cpp
@@ -172,7 +172,7 @@ bool GattCharacteristic::callOnUpdatedValue(GDBusConnection *pConnection, void *
return false;
}
- Logger::trace(SSTR << "Calling OnUpdatedValue function for interface at path '" << getPath() << "'");
+ Logger::debug(SSTR << "Calling OnUpdatedValue function for interface at path '" << getPath() << "'");
return pOnUpdatedValueFunc(*this, pConnection, pUserData);
}
diff --git a/src/GattDescriptor.cpp b/src/GattDescriptor.cpp
index bd29889..c5ecf67 100644
--- a/src/GattDescriptor.cpp
+++ b/src/GattDescriptor.cpp
@@ -173,7 +173,7 @@ bool GattDescriptor::callOnUpdatedValue(GDBusConnection *pConnection, void *pUse
return false;
}
- Logger::trace(SSTR << "Calling OnUpdatedValue function for interface at path '" << getPath() << "'");
+ Logger::debug(SSTR << "Calling OnUpdatedValue function for interface at path '" << getPath() << "'");
return pOnUpdatedValueFunc(*this, pConnection, pUserData);
}
diff --git a/src/Globals.h b/src/Globals.h
index 02b7fa0..8476659 100644
--- a/src/Globals.h
+++ b/src/Globals.h
@@ -34,38 +34,10 @@
#include <string>
-// The name for this controller, as advertised over LE
-//
-// IMPORTANT: Setting the advertisingName will change the system-wide name of the device. If that's not what you want, set BOTH
-// kCustomGlobalAdvertisingName and kCustomGlobalAdvertisingShortName to as empty string ("") to prevent setting the advertising
-// name.
-#define kCustomGlobalAdvertisingName std::string("Gobbledegook")
-
-// The short name for this controller, as advertised over LE
-//
-// According to the spec, the short name is used in case the full name doesn't fit within Extended Inquiry Response (EIR) or
-// Advertising Data (AD).
-//
-// IMPORTANT: Setting the advertisingName will change the system-wide name of the device. If that's not what you want, set BOTH
-// kCustomGlobalAdvertisingName and kCustomGlobalAdvertisingShortName to as empty string ("") to prevent setting the advertising
-// name.
-#define kCustomGlobalAdvertisingShortName std::string("Gobbledegook")
-
-// The name of our server (collectino of services)
-//
-// This is used to build the path for our Bluetooth services (and we'll go ahead and use it as the owned name as well for
-// consistency.)
-#define kServerName std::string("gobbledegook")
-
-// Our owned name
-//
-// D-Bus uses owned names to locate servers on the bus. Think of this as a namespace within D-Bus. Building this with the server
-// name, though it's not necessary to do so. We can call this anything we want, really.
-#define kServerOwnedName (std::string("com.") + kServerName)
-
//
// Custom defined errors
//
+
// In order to avoid confusion, we should use the owned name here, so errors are like extensions to that name. This way, if a
// client gets one of these errors, it'll be clear which server it came from.
-#define kErrorNotImplemented (kServerOwnedName + ".NotImplemented")
+#define kErrorNotImplemented (TheServer->getOwnedName() + ".NotImplemented")
diff --git a/src/Gobbledegook.cpp b/src/Gobbledegook.cpp
index 43e7e76..f2e3ef8 100644
--- a/src/Gobbledegook.cpp
+++ b/src/Gobbledegook.cpp
@@ -47,6 +47,7 @@
#include <string.h>
#include <string>
#include <thread>
+#include <memory>
#include <deque>
#include <mutex>
@@ -403,7 +404,41 @@ int ggkWait()
//
// Similarly, the pointer to data returned to the data getter should point to non-volatile memory so that the server can use it
// safely for an indefinite period of time.
-int ggkStart(GGKServerDataGetter getter, GGKServerDataSetter setter, int maxAsyncInitTimeoutMS)
+//
+// pServiceName: The name of our server (collectino of services)
+//
+// !!!IMPORTANT!!!
+//
+// This name must match tha name configured in the D-Bus permissions. See the Readme.md file for more information.
+//
+// This is used to build the path for our Bluetooth services. It also provides the base for the D-Bus owned name (see
+// getOwnedName.)
+//
+// This value will be stored as lower-case only.
+//
+// Retrieve this value using the `getName()` method
+//
+// pAdvertisingName: The name for this controller, as advertised over LE
+//
+// IMPORTANT: Setting the advertisingName will change the system-wide name of the device. If that's not what you want, set
+// BOTH advertisingName and advertisingShortName to as empty string ("") to prevent setting the advertising
+// name.
+//
+// Retrieve this value using the `getAdvertisingName()` method
+//
+// pAdvertisingShortName: The short name for this controller, as advertised over LE
+//
+// According to the spec, the short name is used in case the full name doesn't fit within Extended Inquiry Response (EIR) or
+// Advertising Data (AD).
+//
+// IMPORTANT: Setting the advertisingName will change the system-wide name of the device. If that's not what you want, set
+// BOTH advertisingName and advertisingShortName to as empty string ("") to prevent setting the advertising
+// name.
+//
+// Retrieve this value using the `getAdvertisingShortName()` method
+//
+int ggkStart(const char *pServiceName, const char *pAdvertisingName, const char *pAdvertisingShortName,
+ GGKServerDataGetter getter, GGKServerDataSetter setter, int maxAsyncInitTimeoutMS)
{
//
// Start by capturing the GLib output
@@ -446,7 +481,7 @@ int ggkStart(GGKServerDataGetter getter, GGKServerDataSetter setter, int maxAsyn
Logger::info("Starting GGK server");
// Allocate our server
- TheServer = std::make_shared<Server>(getter, setter);
+ TheServer = std::make_shared<Server>(pServiceName, pAdvertisingName, pAdvertisingShortName, getter, setter);
// Start our server thread
try
diff --git a/src/HciAdapter.cpp b/src/HciAdapter.cpp
index 6d99d69..9000709 100644
--- a/src/HciAdapter.cpp
+++ b/src/HciAdapter.cpp
@@ -344,10 +344,23 @@ bool HciAdapter::filterAndValidateEvents(uint16_t commandCode, std::vector<uint8
size_t dataLength = sizeof(Header) + pEvent->header.dataSize;
if (dataLength > buffer.size())
{
- Logger::error(SSTR << " + Not enough data for the current event");
+ Logger::error(" + Not enough data for the current event");
return false;
}
+ // !HACK! - If the device is connected, then powering off (Command Code 0x0005) returns a Device Disconnect Event (Event
+ // Code 0xC) rather than a Command Complete Event (0x1) like it should.
+ //
+ // We'll fake it here, converting that condition into a Command Complete Event (0x1).
+ if (commandCode == 0x0005 && pEvent->header.code == 0xC)
+ {
+ Logger::debug("!HACK! Converting invalid Disconect Event to Command Complete Event for power-off command");
+ pEvent->header.code = 1;
+ buffer = {0x1, 0x0, 0x0, 0x0, 0x7, 0x0, 0x5, 0x0, 0x0, 0x2, 0x6, 0x0, 0x0};
+ pEvent = reinterpret_cast<ResponseEvent *>(buffer.data());
+ dataLength = sizeof(Header) + pEvent->header.dataSize;
+ }
+
// Check the event type
if (pEvent->header.code < kMinEventType || pEvent->header.code > kMaxEventType)
{
diff --git a/src/Init.cpp b/src/Init.cpp
index 436a4fa..867b166 100644
--- a/src/Init.cpp
+++ b/src/Init.cpp
@@ -176,7 +176,7 @@ bool idleFunc(void *pUserData)
// Is it a characteristic?
if (std::shared_ptr<const GattCharacteristic> pCharacteristic = TRY_GET_CONST_INTERFACE_OF_TYPE(pInterface, GattCharacteristic))
{
- Logger::trace(SSTR << "Processing updated value for interface '" << interfaceName << "' at path '" << objectPath << "'");
+ Logger::debug(SSTR << "Processing updated value for interface '" << interfaceName << "' at path '" << objectPath << "'");
pCharacteristic->callOnUpdatedValue(pBusConnection, pUserData);
}
}
@@ -422,7 +422,7 @@ GVariant *onGetProperty
return nullptr;
}
- Logger::trace(SSTR << "Calling property getter: " << propertyPath);
+ Logger::info(SSTR << "Calling property getter: " << propertyPath);
GVariant *pResult = pProperty->getGetterFunc()(pConnection, pSender, objectPath.c_str(), pInterfaceName, pPropertyName, ppError, pUserData);
if (nullptr == pResult)
@@ -467,7 +467,7 @@ gboolean onSetProperty
return false;
}
- Logger::trace(SSTR << "Calling property getter: " << propertyPath);
+ Logger::info(SSTR << "Calling property getter: " << propertyPath);
if (!pProperty->getSetterFunc()(pConnection, pSender, objectPath.c_str(), pInterfaceName, pPropertyName, pValue, ppError, pUserData))
{
g_set_error(ppError, G_IO_ERROR, G_IO_ERROR_FAILED, ("Property(set) failed: " + propertyPath).c_str(), pSender);
@@ -492,7 +492,7 @@ gboolean onSetProperty
void setRetryFailure()
{
retryTimeStart = time(nullptr);
- Logger::debug(SSTR << " + Will retry this failed operation in about " << kRetryDelaySeconds << " seconds");
+ Logger::warn(SSTR << " + Will retry the failed operation in about " << kRetryDelaySeconds << " seconds");
}
// ---------------------------------------------------------------------------------------------------------------------------------
@@ -534,7 +534,7 @@ void doRegisterApplication()
else
{
g_variant_unref(pVariant);
- Logger::trace(SSTR << "Application registered");
+ Logger::debug(SSTR << "GATT application registered with BlueZ");
bApplicationRegistered = true;
}
@@ -664,7 +664,7 @@ void configureAdapter()
Mgmt mgmt;
// Find out what our current settings are
- Logger::trace(SSTR << "Getting device information");
+ Logger::debug(SSTR << "Getting device information");
Mgmt::ControllerInformation *pInfo = mgmt.getControllerInformation();
if (nullptr == pInfo)
{
@@ -675,7 +675,7 @@ void configureAdapter()
// We need it off to start with
if ((pInfo->currentSettings & Mgmt::EHciPowered) != 0)
{
- Logger::trace(SSTR << "Powering off");
+ Logger::debug(SSTR << "Powering off");
if (!mgmt.setPowered(false))
{
setRetryFailure();
@@ -687,7 +687,7 @@ void configureAdapter()
bool bredrCurrentState = (pInfo->currentSettings & Mgmt::EHciBasicRate_EnhancedDataRate) != 0 ? true:false;
if (TheServer->getEnableBREDR() != bredrCurrentState)
{
- Logger::trace(SSTR << (TheServer->getEnableBREDR() ? "Enabling":"Disabling") << " BR/EDR");
+ Logger::debug(SSTR << (TheServer->getEnableBREDR() ? "Enabling":"Disabling") << " BR/EDR");
if (!mgmt.setBredr(TheServer->getEnableBREDR()))
{
setRetryFailure();
@@ -699,7 +699,7 @@ void configureAdapter()
bool scCurrentState = (pInfo->currentSettings & Mgmt::EHciSecureConnections) != 0 ? true:false;
if (TheServer->getEnableSecureConnection() != scCurrentState)
{
- Logger::trace(SSTR << (TheServer->getEnableSecureConnection() ? "Enabling":"Disabling") << " Secure Connections");
+ Logger::debug(SSTR << (TheServer->getEnableSecureConnection() ? "Enabling":"Disabling") << " Secure Connections");
if (!mgmt.setSecureConnections(TheServer->getEnableSecureConnection() ? 1 : 0))
{
setRetryFailure();
@@ -711,7 +711,7 @@ void configureAdapter()
bool bondableCurrentState = (pInfo->currentSettings & Mgmt::EHciBondable) != 0 ? true:false;
if (TheServer->getEnableBondable() != bondableCurrentState)
{
- Logger::trace(SSTR << (TheServer->getEnableBondable() ? "Enabling":"Disabling") << " Bondable");
+ Logger::debug(SSTR << (TheServer->getEnableBondable() ? "Enabling":"Disabling") << " Bondable");
if (!mgmt.setBondable(TheServer->getEnableBondable()))
{
setRetryFailure();
@@ -723,7 +723,7 @@ void configureAdapter()
bool connectableCurrentState = (pInfo->currentSettings & Mgmt::EHciConnectable) != 0 ? true:false;
if (TheServer->getEnableConnectable() != connectableCurrentState)
{
- Logger::trace(SSTR << (TheServer->getEnableConnectable() ? "Enabling":"Disabling") << " Connectable");
+ Logger::debug(SSTR << (TheServer->getEnableConnectable() ? "Enabling":"Disabling") << " Connectable");
if (!mgmt.setConnectable(TheServer->getEnableConnectable()))
{
setRetryFailure();
@@ -734,7 +734,7 @@ void configureAdapter()
// Enable the LE state (we always set this state if it's not set)
if ((pInfo->currentSettings & Mgmt::EHciLowEnergy) == 0)
{
- Logger::trace(SSTR << "Enabling LE");
+ Logger::debug(SSTR << "Enabling LE");
if (!mgmt.setLE(true))
{
setRetryFailure();
@@ -746,7 +746,7 @@ void configureAdapter()
bool advertisingCurrentState = (pInfo->currentSettings & Mgmt::EHciAdvertising) != 0 ? true:false;
if (TheServer->getEnableAdvertising() != advertisingCurrentState)
{
- Logger::trace(SSTR << (TheServer->getEnableAdvertising() ? "Enabling":"Disabling") << " Advertising");
+ Logger::debug(SSTR << (TheServer->getEnableAdvertising() ? "Enabling":"Disabling") << " Advertising");
if (!mgmt.setAdvertising(TheServer->getEnableAdvertising() ? 1 : 0))
{
setRetryFailure();
@@ -755,22 +755,25 @@ void configureAdapter()
}
// Set the name?
- if (kCustomGlobalAdvertisingName.length() != 0 || kCustomGlobalAdvertisingShortName.length() != 0)
+ if (TheServer->getAdvertisingName().length() != 0 || TheServer->getAdvertisingShortName().length() != 0)
{
- if (Mgmt::truncateName(kCustomGlobalAdvertisingName) != pInfo->name ||
- Mgmt::truncateShortName(kCustomGlobalAdvertisingShortName) != pInfo->shortName)
+ std::string advertisingName = Mgmt::truncateName(TheServer->getAdvertisingName());
+ std::string advertisingShortName = Mgmt::truncateShortName(TheServer->getAdvertisingShortName());
+
+ if (advertisingName != pInfo->name || advertisingShortName != pInfo->shortName)
{
- Logger::trace(SSTR << "Setting name to '" << kCustomGlobalAdvertisingName << "'");
- if (!mgmt.setName(kCustomGlobalAdvertisingName.c_str(), kCustomGlobalAdvertisingName.c_str()))
+ if (!mgmt.setName(advertisingName.c_str(), advertisingShortName.c_str()))
{
setRetryFailure();
return;
}
}
+
+ Logger::info(SSTR << "BLE advertising name set to '" << advertisingName << "' (with short name: '" << advertisingShortName << "')");
}
// Turn it back on
- Logger::trace(SSTR << "Powering on");
+ Logger::debug(SSTR << "Powering on");
if (!mgmt.setPowered(true))
{
setRetryFailure();
@@ -944,9 +947,9 @@ void doOwnedNameAcquire()
ownedNameId = g_bus_own_name_on_connection
(
- pBusConnection, // GDBusConnection *connection
- kServerOwnedName.c_str(), // const gchar *name
- G_BUS_NAME_OWNER_FLAGS_NONE, // GBusNameOwnerFlags flags
+ pBusConnection, // GDBusConnection *connection
+ TheServer->getOwnedName().c_str(), // const gchar *name
+ G_BUS_NAME_OWNER_FLAGS_NONE, // GBusNameOwnerFlags flags
// GBusNameAcquiredCallback name_acquired_handler
[](GDBusConnection *, const gchar *, gpointer)
@@ -973,16 +976,16 @@ void doOwnedNameAcquire()
// Bus name lost
bOwnedNameAcquired = false;
- // If we don't have a periodicTimeout (which we use for error recovery) then we're done
+ // If we don't have a periodicTimeout (which we use for error recovery) then we're sunk
if (0 == periodicTimeoutId)
{
- Logger::fatal(SSTR << "Unable to acquire an owned name ('" << kServerOwnedName << "') on the bus");
+ Logger::fatal(SSTR << "Unable to acquire an owned name ('" << TheServer->getOwnedName() << "') on the bus");
setServerHealth(EFailedInit);
shutdown();
}
else
{
- Logger::warn(SSTR << "Owned name ('" << kServerOwnedName << "') lost");
+ Logger::warn(SSTR << "Owned name ('" << TheServer->getOwnedName() << "') lost");
setRetryFailure();
return;
}
@@ -1060,7 +1063,7 @@ void initializationStateProcessor()
//
if (nullptr == pBusConnection)
{
- Logger::trace(SSTR << "Acquiring bus connection");
+ Logger::debug(SSTR << "Acquiring bus connection");
doBusAcquire();
return;
}
@@ -1070,7 +1073,7 @@ void initializationStateProcessor()
//
if (!bOwnedNameAcquired)
{
- Logger::trace(SSTR << "Acquiring owned name: '" << kServerOwnedName << "'");
+ Logger::debug(SSTR << "Acquiring owned name: '" << TheServer->getOwnedName() << "'");
doOwnedNameAcquire();
return;
}
@@ -1090,7 +1093,7 @@ void initializationStateProcessor()
//
if (bluezGattManagerInterfaceName.empty())
{
- Logger::trace(SSTR << "Finding BlueZ GattManager1 interface");
+ Logger::debug(SSTR << "Finding BlueZ GattManager1 interface");
findAdapterInterface();
return;
}
@@ -1100,7 +1103,7 @@ void initializationStateProcessor()
//
if (!bAdapterConfigured)
{
- Logger::trace(SSTR << "Configuring BlueZ adapter '" << bluezGattManagerInterfaceName << "'");
+ Logger::debug(SSTR << "Configuring BlueZ adapter '" << bluezGattManagerInterfaceName << "'");
configureAdapter();
return;
}
@@ -1110,7 +1113,7 @@ void initializationStateProcessor()
//
if (registeredObjectIds.empty())
{
- Logger::trace(SSTR << "Registering with D-Bus");
+ Logger::debug(SSTR << "Registering with D-Bus");
registerObjects();
return;
}
@@ -1118,7 +1121,7 @@ void initializationStateProcessor()
// Register our appliation with the BlueZ GATT manager
if (!bApplicationRegistered)
{
- Logger::trace(SSTR << "Registering application with BlueZ GATT manager");
+ Logger::debug(SSTR << "Registering application with BlueZ GATT manager");
doRegisterApplication();
return;
@@ -1167,7 +1170,7 @@ void runServerThread()
// There are alternatives, but using async methods is the recommended way.
initializationStateProcessor();
- Logger::trace(SSTR << "Starting main loop");
+ Logger::debug(SSTR << "Starting GLib main loop");
pMainLoop = g_main_loop_new(NULL, FALSE);
// Add the idle function
diff --git a/src/Mgmt.cpp b/src/Mgmt.cpp
index c956e99..34537f0 100644
--- a/src/Mgmt.cpp
+++ b/src/Mgmt.cpp
@@ -139,8 +139,8 @@ Mgmt::ControllerInformation *Mgmt::getControllerInformation()
// Set the adapter name and short name
//
// The inputs `name` and `shortName` may be truncated prior to setting them on the adapter. To ensure that `name` and
-// `shortName` conform to length specifications prior to calling this method, see the constants `kMaxNameLength` and
-// `kMaxShortNameLength`. In addition, the static methods `truncateName()` and `truncateShortName()` may be helpful.
+// `shortName` conform to length specifications prior to calling this method, see the constants `kMaxAdvertisingNameLength` and
+// `kMaxAdvertisingShortNameLength`. In addition, the static methods `truncateName()` and `truncateShortName()` may be helpful.
//
// Returns true on success, otherwise false
bool Mgmt::setName(std::string name, std::string shortName)
@@ -179,7 +179,7 @@ bool Mgmt::setName(std::string name, std::string shortName)
return false;
}
- Logger::trace(SSTR << " + Name set to '" << request.name << "', short name set to '" << request.shortName << "'");
+ Logger::info(SSTR << " + Name set to '" << request.name << "', short name set to '" << request.shortName << "'");
return true;
}
@@ -214,24 +214,13 @@ bool Mgmt::setState(const char *pSettingName, uint16_t commandCode, uint16_t con
SResponse response;
if (!hciAdapter.sendCommand(request, response, sizeof(response)))
{
- // Setting power to 0 doesn't actually return a response event if it's connected (it receives a disconnect instead).
- //
- // This is a failure on the part of GGK because it should be handling events more correctly. For now, though, we'll just
- // turn those failures into debug log messages so our logs aren't cluttered up with false failures.
- if (commandCode == 0x0005)
- {
- Logger::debug(SSTR << " + Failed to set " << pSettingName << " state to: " << static_cast<int>(newState));
- }
- else
- {
- Logger::info(SSTR << " + Failed to set " << pSettingName << " state to: " << static_cast<int>(newState));
- }
+ Logger::warn(SSTR << " + Failed to set " << pSettingName << " state to: " << static_cast<int>(newState));
return false;
}
response.toHost();
- Logger::trace(SSTR << " + " << pSettingName << " set to " << static_cast<int>(newState) << ": " << controllerSettingsString(response.currentSettings));
+ Logger::debug(SSTR << " + " << pSettingName << " set to " << static_cast<int>(newState) << ": " << controllerSettingsString(response.currentSettings));
return true;
}
@@ -331,24 +320,24 @@ std::string Mgmt::controllerSettingsString(uint32_t bits)
// `name` is returned.
std::string Mgmt::truncateName(const std::string &name)
{
- if (name.length() <= kMaxNameLength)
+ if (name.length() <= kMaxAdvertisingNameLength)
{
return name;
}
- return name.substr(0, kMaxNameLength);
+ return name.substr(0, kMaxAdvertisingNameLength);
}
// Truncates the string `name` to the maximum allowed length for an adapter short-name. If `name` needs no truncation, a copy
// of `name` is returned.
std::string Mgmt::truncateShortName(const std::string &name)
{
- if (name.length() <= kMaxShortNameLength)
+ if (name.length() <= kMaxAdvertisingShortNameLength)
{
return name;
}
- return name.substr(0, kMaxShortNameLength);
+ return name.substr(0, kMaxAdvertisingShortNameLength);
}
}; // namespace ggk \ No newline at end of file
diff --git a/src/Mgmt.h b/src/Mgmt.h
index dfd5b95..23315a5 100644
--- a/src/Mgmt.h
+++ b/src/Mgmt.h
@@ -50,10 +50,10 @@ struct Mgmt
//
// The length of the controller's name (not including null terminator)
- static const int kMaxNameLength = 248;
+ static const int kMaxAdvertisingNameLength = 248;
// The length of the controller's short name (not including null terminator)
- static const int kMaxShortNameLength = 10;
+ static const int kMaxAdvertisingShortNameLength = 10;
//
// Types
@@ -127,8 +127,8 @@ struct Mgmt
// Set the adapter name and short name
//
// The inputs `name` and `shortName` may be truncated prior to setting them on the adapter. To ensure that `name` and
- // `shortName` conform to length specifications prior to calling this method, see the constants `kMaxNameLength` and
- // `kMaxShortNameLength`. In addition, the static methods `truncateName()` and `truncateShortName()` may be helpful.
+ // `shortName` conform to length specifications prior to calling this method, see the constants `kMaxAdvertisingNameLength` and
+ // `kMaxAdvertisingShortNameLength`. In addition, the static methods `truncateName()` and `truncateShortName()` may be helpful.
//
// Returns true on success, otherwise false
bool setName(std::string name, std::string shortName);
diff --git a/src/Server.cpp b/src/Server.cpp
index a369b32..87b3279 100644
--- a/src/Server.cpp
+++ b/src/Server.cpp
@@ -62,8 +62,6 @@
// used to generate both: (1) the D-Bus object hierarchy and (2) the BlueZ services that occupy that hierarchy. In addition, we'll
// take that a step further by including the implementation right inside the description. Everything in one place.
//
-// Well, almost one place (hint: Take a quick look at Globals.h - that's where your server name is.)
-//
// >>
// >>> MANAGING SERVER DATA
// >>
@@ -160,6 +158,8 @@
// https://www.freedesktop.org/software/gstreamer-sdk/data/docs/latest/glib/glib-GVariantType.html
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#include <algorithm>
+
#include "Server.h"
#include "ServerUtils.h"
#include "Utils.h"
@@ -171,6 +171,7 @@
#include "GattUuid.h"
#include "GattCharacteristic.h"
#include "GattDescriptor.h"
+#include "Logger.h"
namespace ggk {
@@ -195,11 +196,45 @@ std::shared_ptr<Server> TheServer = nullptr;
// Object implementation
// ---------------------------------------------------------------------------------------------------------------------------------
-// Create (and completely describe) a server
+// Our constructor builds our entire server description
+//
+// serviceName: The name of our server (collectino of services)
+//
+// This is used to build the path for our Bluetooth services. It also provides the base for the D-Bus owned name (see
+// getOwnedName.)
+//
+// This value will be stored as lower-case only.
+//
+// Retrieve this value using the `getName()` method.
+//
+// advertisingName: The name for this controller, as advertised over LE
//
-// For details, head up to the top of this file.
-Server::Server(GGKServerDataGetter getter, GGKServerDataSetter setter)
+// IMPORTANT: Setting the advertisingName will change the system-wide name of the device. If that's not what you want, set
+// BOTH advertisingName and advertisingShortName to as empty string ("") to prevent setting the advertising
+// name.
+//
+// Retrieve this value using the `getAdvertisingName()` method.
+//
+// advertisingShortName: The short name for this controller, as advertised over LE
+//
+// According to the spec, the short name is used in case the full name doesn't fit within Extended Inquiry Response (EIR) or
+// Advertising Data (AD).
+//
+// IMPORTANT: Setting the advertisingName will change the system-wide name of the device. If that's not what you want, set
+// BOTH advertisingName and advertisingShortName to as empty string ("") to prevent setting the advertising
+// name.
+//
+// Retrieve this value using the `getAdvertisingShortName()` method.
+//
+Server::Server(const std::string &serviceName, const std::string &advertisingName, const std::string &advertisingShortName,
+ GGKServerDataGetter getter, GGKServerDataSetter setter)
{
+ // Save our names
+ this->serviceName = serviceName;
+ std::transform(this->serviceName.begin(), this->serviceName.end(), this->serviceName.begin(), ::tolower);
+ this->advertisingName = advertisingName;
+ this->advertisingShortName = advertisingShortName;
+
// Register getter & setter for server data
dataGetter = getter;
dataSetter = setter;
@@ -216,7 +251,7 @@ Server::Server(GGKServerDataGetter getter, GGKServerDataSetter setter)
//
// Create the root D-Bus object and push it into the list
- objects.push_back(DBusObject(DBusObjectPath() + "com" + kServerName));
+ objects.push_back(DBusObject(DBusObjectPath() + "com" + getServiceName()));
// We're going to build off of this object, so we need to get a reference to the instance of the object as it resides in the
// list (and not the object that would be added to the list.)
diff --git a/src/Server.h b/src/Server.h
index 8312022..d6154dc 100644
--- a/src/Server.h
+++ b/src/Server.h
@@ -35,11 +35,13 @@
#pragma once
+#include <gio/gio.h>
#include <string>
+#include <vector>
#include <list>
#include <memory>
-#include "DBusInterface.h"
+#include "../include/Gobbledegook.h"
#include "DBusObject.h"
namespace ggk {
@@ -49,6 +51,9 @@ namespace ggk {
//
struct GattProperty;
+struct GattCharacteristic;
+struct DBusInterface;
+struct DBusObjectPath;
//
// Implementation
@@ -91,12 +96,77 @@ struct Server
// Returns our registered data setter
GGKServerDataSetter getDataSetter() const { return dataSetter; }
+ // advertisingName: The name for this controller, as advertised over LE
+ //
+ // This is set from the constructor.
+ //
+ // IMPORTANT: Setting the advertisingName will change the system-wide name of the device. If that's not what you want, set
+ // BOTH advertisingName and advertisingShortName to as empty string ("") to prevent setting the advertising
+ // name.
+ const std::string &getAdvertisingName() const { return advertisingName; }
+
+ // advertisingShortName: The short name for this controller, as advertised over LE
+ //
+ // According to the spec, the short name is used in case the full name doesn't fit within Extended Inquiry Response (EIR) or
+ // Advertising Data (AD).
+ //
+ // This is set from the constructor.
+ //
+ // IMPORTANT: Setting the advertisingName will change the system-wide name of the device. If that's not what you want, set
+ // BOTH advertisingName and advertisingShortName to as empty string ("") to prevent setting the advertising
+ // name.
+ const std::string &getAdvertisingShortName() const { return advertisingShortName; }
+
+ // serviceName: The name of our server (collectino of services)
+ //
+ // This is set from the constructor.
+ //
+ // This is used to build the path for our Bluetooth services (and we'll go ahead and use it as the owned name as well for
+ // consistency.)
+ const std::string &getServiceName() const { return serviceName; }
+
+ // Our owned name
+ //
+ // D-Bus uses owned names to locate servers on the bus. Think of this as a namespace within D-Bus. We building this with the
+ // server name to keep things simple.
+ std::string getOwnedName() const { return std::string("com.") + getServiceName(); }
+
//
// Initialization
//
// Our constructor builds our entire server description
- Server(GGKServerDataGetter getter, GGKServerDataSetter setter);
+ //
+ // serviceName: The name of our server (collectino of services)
+ //
+ // This is used to build the path for our Bluetooth services. It also provides the base for the D-Bus owned name (see
+ // getOwnedName.)
+ //
+ // This value will be stored as lower-case only.
+ //
+ // Retrieve this value using the `getName()` method.
+ //
+ // advertisingName: The name for this controller, as advertised over LE
+ //
+ // IMPORTANT: Setting the advertisingName will change the system-wide name of the device. If that's not what you want, set
+ // BOTH advertisingName and advertisingShortName to as empty string ("") to prevent setting the advertising
+ // name.
+ //
+ // Retrieve this value using the `getAdvertisingName()` method.
+ //
+ // advertisingShortName: The short name for this controller, as advertised over LE
+ //
+ // According to the spec, the short name is used in case the full name doesn't fit within Extended Inquiry Response (EIR) or
+ // Advertising Data (AD).
+ //
+ // IMPORTANT: Setting the advertisingName will change the system-wide name of the device. If that's not what you want, set
+ // BOTH advertisingName and advertisingShortName to as empty string ("") to prevent setting the advertising
+ // name.
+ //
+ // Retrieve this value using the `getAdvertisingShortName()` method.
+ //
+ Server(const std::string &serviceName, const std::string &advertisingName, const std::string &advertisingShortName,
+ GGKServerDataGetter getter, GGKServerDataSetter setter);
//
// Utilitarian
@@ -142,6 +212,35 @@ private:
// The setter callback that is responsible for storing current server data that is shared over Bluetooth
GGKServerDataSetter dataSetter;
+
+ // advertisingName: The name for this controller, as advertised over LE
+ //
+ // This is set from the constructor.
+ //
+ // IMPORTANT: Setting the advertisingName will change the system-wide name of the device. If that's not what you want, set
+ // BOTH advertisingName and advertisingShortName to as empty string ("") to prevent setting the advertising
+ // name.
+ std::string advertisingName;
+
+ // advertisingShortName: The short name for this controller, as advertised over LE
+ //
+ // According to the spec, the short name is used in case the full name doesn't fit within Extended Inquiry Response (EIR) or
+ // Advertising Data (AD).
+ //
+ // This is set from the constructor.
+ //
+ // IMPORTANT: Setting the advertisingName will change the system-wide name of the device. If that's not what you want, set
+ // BOTH advertisingName and advertisingShortName to as empty string ("") to prevent setting the advertising
+ // name.
+ std::string advertisingShortName;
+
+ // serviceName: The name of our server (collectino of services)
+ //
+ // This is set from the constructor.
+ //
+ // This is used to build the path for our Bluetooth services (and we'll go ahead and use it as the owned name as well for
+ // consistency.)
+ std::string serviceName;
};
// Our one and only server. It's a global.
diff --git a/src/Utils.cpp b/src/Utils.cpp
index ca3aaa5..2ced142 100644
--- a/src/Utils.cpp
+++ b/src/Utils.cpp
@@ -180,7 +180,7 @@ std::string Utils::hex(const uint8_t *pData, int count)
asciiData.push_back(line);
}
- std::string result = "\n";
+ std::string result = "";
size_t dataSize = hexData.size();
for (size_t i = 0; i < dataSize; ++i)
{
diff --git a/src/standalone.cpp b/src/standalone.cpp
index c8af5d6..3c4968c 100644
--- a/src/standalone.cpp
+++ b/src/standalone.cpp
@@ -293,7 +293,13 @@ int main(int argc, char **ppArgv)
// Start the server's ascync processing
//
// This starts the server on a thread and begins the initialization process
- if (!ggkStart(dataGetter, dataSetter, kMaxAsyncInitTimeoutMS))
+ //
+ // !!!IMPORTANT!!!
+ //
+ // This first parameter (the service name) must match tha name configured in the D-Bus permissions. See the Readme.md file
+ // for more information.
+ //
+ if (!ggkStart("gobbledegook", "Gobbledegook", "Gobbledegook", dataGetter, dataSetter, kMaxAsyncInitTimeoutMS))
{
return -1;
}