syncevolution/src/dbus/server/bluez-manager.h
Patrick Ohly b34591dd62 GDBus: API and usage cleanup
DBusCallObject and friends were not used anywhere. Removed.

DBusObject and DBusRemoteObject used pure virtual methods to let
derived classes provide information about interface, path,
destination, method and the connection. The idea behind that was that
most of these strings are static and thus do not need to be copied.

The downside is that one had to derive from these classes in order to
provide the required information. The same class could not own two
instances of the generic DBusObject to access two different
destinations. It also sprinkled the code for setting up D-Bus
operations into several different places (constructor, class definition).

Now the information is passed to the DBus[Remote]Object constructor
and stored in the classes, which are thus merely containers for the
information and thus easier to use. Users of the classes still derive
from them, to keep the change smaller, although that is no longer
necessary.

Removed plain DBusConnection pointers from the C++ interface, return
DBusConnectionPtr instead. The exception is DBusObject, which still
returns plain pointers owned by the instance (as before) to ease
integration with the underlying D-Bus library. DBUS_CONNECTION_TYPE
is not needed.

This revealed that quite some code incorrectly took another reference
to the connection when assigning to DBusConnectionPtr (assignment
always increases the refcount, only in the constructor is that
optional). As a result the private connections were never
destructed. Apparently there were some global pointers to active
connections, so that this (minor) resource leak didn't show up in
valgrind.

It also showed that the closing of the D-Bus connection never happened
properly, although libdbus requires it. The ref counting mechanism
cannot be used for this because it cannot be checked whether the last
reference is about to be dropped. The slightly hackish solution is to
designate one DBusObject as the "main owner" of the connection. When
that object destructs, it closes the connection. There might still be
some other references; they simply cannot (and shouldn't) send or
receive messages anymore.
2011-12-19 17:59:42 +01:00

197 lines
7.4 KiB
C++

/*
* Copyright (C) 2011 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) version 3.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#ifndef BLUEZ_MANAGER_H
#define BLUEZ_MANAGER_H
#include <string>
#include "gdbus-cxx-bridge.h"
#include <boost/utility.hpp>
#include <syncevo/declarations.h>
SE_BEGIN_CXX
class Server;
class GLibNotify;
/**
* Query bluetooth devices from org.bluez
* The basic workflow is:
* 1) get default adapter from bluez by calling 'DefaultAdapter' method of org.bluez.Manager
* 2) get all devices of the adapter by calling 'ListDevices' method of org.bluez.Adapter
* 3) iterate all devices and get properties for each one by calling 'GetProperties' method of org.bluez.Device.
* Then check its UUIDs whether it contains sync services and put it in the sync device list if it is. If this
* is a sync device we then call DiscoverServices to check for the PnPInformation service record.
*
* To track changes of devices dynamically, here also listen signals from bluez:
* org.bluez.Manager - DefaultAdapterChanged: default adapter is changed and thus have to get its devices
* and update sync device list
* org.bluez.Adapter - DeviceCreated, DeviceRemoved: device is created or removed and device list is updated
* org.bluez.Device - PropertyChanged: property is changed and device information is changed and tracked
*
* This class is to manage querying bluetooth devices from org.bluez. Also
* it acts a proxy to org.bluez.Manager.
*/
class BluezManager : public GDBusCXX::DBusRemoteObject {
public:
BluezManager(Server &server);
bool isDone() { return m_done; }
private:
class BluezDevice;
/**
* This class acts a proxy to org.bluez.Adapter.
* Call methods of org.bluez.Adapter and listen signals from it
* to get devices list and track its changes
*/
class BluezAdapter: public GDBusCXX::DBusRemoteObject
{
public:
BluezAdapter (BluezManager &manager, const std::string &path);
void checkDone(bool forceDone = false)
{
if(forceDone || m_devReplies >= m_devNo) {
m_devReplies = m_devNo = 0;
m_manager.setDone(true);
} else {
m_manager.setDone(false);
}
}
std::vector<boost::shared_ptr<BluezDevice> >& getDevices() { return m_devices; }
private:
/** callback of 'ListDevices' signal. Used to get all available devices of the adapter */
void listDevicesCb(const std::vector<GDBusCXX::DBusObject_t> &devices, const std::string &error);
/** callback of 'DeviceRemoved' signal. Used to track a device is removed */
void deviceRemoved(const GDBusCXX::DBusObject_t &object);
/** callback of 'DeviceCreated' signal. Used to track a new device is created */
void deviceCreated(const GDBusCXX::DBusObject_t &object);
BluezManager &m_manager;
/** the number of device for the default adapter */
int m_devNo;
/** the number of devices having reply */
int m_devReplies;
/** all available devices */
std::vector<boost::shared_ptr<BluezDevice> > m_devices;
/** represents 'DeviceRemoved' signal of org.bluez.Adapter*/
GDBusCXX::SignalWatch1<GDBusCXX::DBusObject_t> m_deviceRemoved;
/** represents 'DeviceAdded' signal of org.bluez.Adapter*/
GDBusCXX::SignalWatch1<GDBusCXX::DBusObject_t> m_deviceAdded;
friend class BluezDevice;
};
/**
* This class acts a proxy to org.bluez.Device.
* Call methods of org.bluez.Device and listen signals from it
* to get properties of device and track its changes
*/
class BluezDevice: public GDBusCXX::DBusRemoteObject
{
public:
typedef std::map<std::string, boost::variant<std::vector<std::string>, std::string > > PropDict;
typedef std::map<uint32_t, std::string> ServiceDict;
BluezDevice (BluezAdapter &adapter, const std::string &path);
std::string getMac() { return m_mac; }
/**
* check whether the current device has sync service if yes,
* put it in the adapter's sync devices list
*/
void checkSyncService(const std::vector<std::string> &uuids);
private:
/** callback of 'GetProperties' method. The properties of the device is gotten */
void getPropertiesCb(const PropDict &props, const std::string &error);
/** callback of 'DiscoverServices' method. The service records are retrieved */
void discoverServicesCb(const ServiceDict &serviceDict, const std::string &error);
/** callback of 'PropertyChanged' signal. Changed property is tracked */
void propertyChanged(const std::string &name, const boost::variant<std::vector<std::string>, std::string> &prop);
BluezAdapter &m_adapter;
/** name of the device */
std::string m_name;
/** mac address of the device */
std::string m_mac;
/** whether the calling of 'GetProperties' is returned */
bool m_reply;
typedef GDBusCXX::SignalWatch2<std::string, boost::variant<std::vector<std::string>, std::string> > PropertySignal;
/** represents 'PropertyChanged' signal of org.bluez.Device */
PropertySignal m_propertyChanged;
friend class BluezAdapter;
};
/*
* check whether the data is generated. If errors, force initilization done
*/
void setDone(bool done) { m_done = done; }
/** callback of 'DefaultAdapter' method to get the default bluetooth adapter */
void defaultAdapterCb(const GDBusCXX::DBusObject_t &adapter, const std::string &error);
/** callback of 'DefaultAdapterChanged' signal to track changes of the default adapter */
void defaultAdapterChanged(const GDBusCXX::DBusObject_t &adapter);
Server &m_server;
GDBusCXX::DBusConnectionPtr m_bluezConn;
boost::shared_ptr<BluezAdapter> m_adapter;
// Holds the bluetooth lookup table and whether it was successfully loaded.
class lookupTable : private boost::noncopyable {
public:
lookupTable() : bt_key_file(NULL), isLoaded(false) {}
~lookupTable() { if (bt_key_file) g_key_file_free(bt_key_file); }
GKeyFile *bt_key_file;
bool isLoaded;
} m_lookupTable;
boost::shared_ptr<GLibNotify> m_watchedFile;
void loadBluetoothDeviceLookupTable();
bool getPnpInfoNamesFromValues(const std::string &vendorValue, std::string &vendorName,
const std::string &productValue, std::string &productName);
/** represents 'DefaultAdapterChanged' signal of org.bluez.Adapter*/
GDBusCXX::SignalWatch1<GDBusCXX::DBusObject_t> m_adapterChanged;
/** flag to indicate whether the calls are all returned */
bool m_done;
};
SE_END_CXX
#endif // BLUEZ_MANAGER_H