summaryrefslogtreecommitdiff
path: root/cpp/src/IceBT/Engine.cpp
diff options
context:
space:
mode:
authorMark Spruiell <mes@zeroc.com>2015-11-20 12:16:36 -0800
committerMark Spruiell <mes@zeroc.com>2015-11-20 12:16:36 -0800
commite128779da2d66f7fc1d2e280b3fa4b9cf70a8339 (patch)
tree87d78542dce72245c7f755bf3e9f6588ebc6e5d8 /cpp/src/IceBT/Engine.cpp
parentadding destroy() method to IceXML classes (diff)
downloadice-e128779da2d66f7fc1d2e280b3fa4b9cf70a8339.tar.bz2
ice-e128779da2d66f7fc1d2e280b3fa4b9cf70a8339.tar.xz
ice-e128779da2d66f7fc1d2e280b3fa4b9cf70a8339.zip
initial BlueZ 4 implementation
Diffstat (limited to 'cpp/src/IceBT/Engine.cpp')
-rw-r--r--cpp/src/IceBT/Engine.cpp1409
1 files changed, 502 insertions, 907 deletions
diff --git a/cpp/src/IceBT/Engine.cpp b/cpp/src/IceBT/Engine.cpp
index 14dc424b198..878deec1f73 100644
--- a/cpp/src/IceBT/Engine.cpp
+++ b/cpp/src/IceBT/Engine.cpp
@@ -14,6 +14,7 @@
#include <IceUtil/StringUtil.h>
#include <IceUtil/Thread.h>
#include <IceUtil/UUID.h>
+#include <IceXML/Parser.h>
#include <stack>
@@ -23,306 +24,59 @@ using namespace IceBT;
IceUtil::Shared* IceBT::upCast(IceBT::Engine* p) { return p; }
-namespace IceBT
-{
-
-class ConnectionI;
-typedef IceUtil::Handle<ConnectionI> ConnectionIPtr;
+typedef map<string, DBus::VariantValuePtr> VariantMap;
-//
-// ConnectionI implements IceBT::Connection and encapsulates a DBus connection along with
-// some additional state.
-//
-class ConnectionI : public Connection
+namespace
{
-public:
-
- ConnectionI(const DBus::ConnectionPtr& conn, const string& devicePath, const string& uuid) :
- _connection(conn),
- _devicePath(devicePath),
- _uuid(uuid)
- {
- }
-
- DBus::ConnectionPtr dbusConnection() const
- {
- return _connection;
- }
+void extractProperties(const DBus::ValuePtr& v, VariantMap& vm)
+{
//
- // Blocking close.
+ // The given value is a dictionary structured like this:
+ //
+ // Key: Property name
+ // Value: Property value (variant)
//
- virtual void close()
- {
- try
- {
- //
- // Invoke DisconnectProfile to terminate the client-side connection.
- //
- DBus::MessagePtr msg =
- DBus::Message::createCall("org.bluez", _devicePath, "org.bluez.Device1", "DisconnectProfile");
- msg->write(new DBus::StringValue(_uuid));
- DBus::AsyncResultPtr r = _connection->callAsync(msg);
- r->waitUntilFinished(); // Block until the call completes.
- }
- catch(const DBus::Exception&)
- {
- // Ignore.
- }
-
- try
- {
- _connection->close();
- }
- catch(const DBus::Exception&)
- {
- // Ignore.
- }
- }
-
-private:
-
- DBus::ConnectionPtr _connection;
- string _devicePath;
- string _uuid;
-};
-
-//
-// Profile is an abstract base class representing a Bluetooth "profile". We have to register a DBus
-// profile object for a UUID in order to receive connection notifications. This is necessary for both
-// outgoing and incoming connections.
-//
-class Profile : public DBus::Service
-{
-public:
-
- virtual void handleMethodCall(const DBus::ConnectionPtr& conn, const DBus::MessagePtr& m)
- {
- string member = m->getMember();
- if(member == "Release")
- {
- //
- // Ignore - no reply necessary.
- //
- }
- else if(member == "NewConnection")
- {
- vector<DBus::ValuePtr> values = m->readAll();
- assert(values.size() == 3);
-
- //
- // This argument is the Unix file descriptor for the new connection.
- //
- DBus::UnixFDValuePtr fd = DBus::UnixFDValuePtr::dynamicCast(values[1]);
- assert(fd);
-
- try
- {
- //
- // Send an empty reply.
- //
- DBus::MessagePtr ret = DBus::Message::createReturn(m);
- conn->sendAsync(ret);
- }
- catch(const DBus::Exception&)
- {
- // Ignore.
- }
-
- try
- {
- newConnection(fd->v);
- }
- catch(...)
- {
- // Ignore.
- }
- }
- else if(member == "RequestDisconnection")
- {
- try
- {
- //
- // Send an empty reply.
- //
- DBus::MessagePtr ret = DBus::Message::createReturn(m);
- conn->sendAsync(ret);
- }
- catch(const DBus::Exception&)
- {
- // Ignore.
- }
-
- //
- // Ignore disconnect requests.
- //
- }
- }
-
-protected:
-
- Profile() {}
-
- virtual void newConnection(int) = 0;
-};
-typedef IceUtil::Handle<Profile> ProfilePtr;
-
-//
-// ClientProfile represents an outgoing connection profile.
-//
-class ClientProfile : public Profile
-{
-public:
-
- ClientProfile(const ConnectionPtr& conn, const ConnectCallbackPtr& cb) :
- _connection(conn),
- _callback(cb)
- {
- }
-
- ~ClientProfile()
- {
- }
-
-protected:
- virtual void newConnection(int fd)
+ assert(v->getType()->getKind() == DBus::Type::KindArray);
+ DBus::ArrayValuePtr props = DBus::ArrayValuePtr::dynamicCast(v);
+ for(vector<DBus::ValuePtr>::const_iterator s = props->elements.begin(); s != props->elements.end(); ++s)
{
- //
- // The callback assumes ownership of the file descriptor and connection.
- //
- _callback->completed(fd, _connection);
- _connection = 0; // Remove circular reference.
- _callback = 0;
+ assert((*s)->getType()->getKind() == DBus::Type::KindDictEntry);
+ DBus::DictEntryValuePtr pe = DBus::DictEntryValuePtr::dynamicCast(*s);
+ assert(pe->key->getType()->getKind() == DBus::Type::KindString);
+ DBus::StringValuePtr propName = DBus::StringValuePtr::dynamicCast(pe->key);
+ assert(pe->value->getType()->getKind() == DBus::Type::KindVariant);
+ vm[propName->v] = DBus::VariantValuePtr::dynamicCast(pe->value);
}
+}
-private:
-
- ConnectionPtr _connection;
- ConnectCallbackPtr _callback;
-};
-typedef IceUtil::Handle<ClientProfile> ClientProfilePtr;
+}
-//
-// ServerProfile represents an incoming connection profile.
-//
-class ServerProfile : public Profile
+namespace IceBT
{
-public:
-
- ServerProfile(const ProfileCallbackPtr& cb) :
- _callback(cb)
- {
- }
-
-protected:
-
- virtual void newConnection(int fd)
- {
- _callback->newConnection(fd);
- }
-
-private:
-
- ProfileCallbackPtr _callback;
-};
-typedef IceUtil::Handle<ServerProfile> ServerProfilePtr;
//
-// Engine delegates to BluetoothService. It encapsulates a snapshot of the "objects" managed by the
-// DBus Bluetooth daemon. These objects include local Bluetooth adapters, paired devices, etc.
+// Engine delegates to BluetoothService.
//
class BluetoothService : public DBus::Filter
{
public:
- typedef map<string, DBus::VariantValuePtr> VariantMap;
typedef map<string, VariantMap> InterfacePropertiesMap;
- struct RemoteDevice
- {
- RemoteDevice()
- {
- }
-
- RemoteDevice(const VariantMap& m) :
- properties(m)
- {
- }
-
- string getAddress() const
- {
- string addr;
- VariantMap::const_iterator i = properties.find("Address");
- if(i != properties.end())
- {
- DBus::StringValuePtr str = DBus::StringValuePtr::dynamicCast(i->second->v);
- assert(str);
- addr = str->v;
- }
- return IceUtilInternal::toUpper(addr);
- }
-
- string getAdapter() const
- {
- string adapter;
- VariantMap::const_iterator i = properties.find("Adapter");
- if(i != properties.end())
- {
- DBus::ObjectPathValuePtr path = DBus::ObjectPathValuePtr::dynamicCast(i->second->v);
- assert(path);
- adapter = path->v;
- }
- return adapter;
- }
-
- VariantMap properties;
- };
-
- struct Adapter
- {
- Adapter()
- {
- }
-
- Adapter(const VariantMap& p) :
- properties(p)
- {
- }
-
- string getAddress() const
- {
- string addr;
- VariantMap::const_iterator i = properties.find("Address");
- if(i != properties.end())
- {
- DBus::StringValuePtr str = DBus::StringValuePtr::dynamicCast(i->second->v);
- assert(str);
- addr = str->v;
- }
- return IceUtilInternal::toUpper(addr);
- }
-
- VariantMap properties;
- vector<DiscoveryCallbackPtr> callbacks;
- };
-
- typedef map<string, RemoteDevice> RemoteDeviceMap; // Key is the object path.
- typedef map<string, Adapter> AdapterMap; // Key is the object path.
-
- BluetoothService()
+ BluetoothService() :
+ _destroyed(false)
{
DBus::initThreads();
try
{
//
- // Block while we establish a DBus connection and retrieve a snapshot of the managed objects
- // from the Bluetooth service.
+ // Block while we establish a DBus connection.
//
_dbusConnection = DBus::Connection::getSystemBus();
_dbusConnection->addFilter(this);
- getManagedObjects();
}
catch(const DBus::Exception& ex)
{
@@ -343,122 +97,84 @@ public:
string intf = msg->getInterface();
string member = msg->getMember();
- if(intf == "org.freedesktop.DBus.ObjectManager" && member == "InterfacesAdded")
+ if(intf == "org.bluez.Adapter" && member == "DeviceFound")
{
//
- // The InterfacesAdded signal contains two values:
+ // The DeviceFound signal contains two values:
//
- // OBJPATH obj_path
- // DICT<STRING,DICT<STRING,VARIANT>> interfaces_and_properties
+ // STRING address
+ // DICT<STRING,VARIANT> properties
//
-
vector<DBus::ValuePtr> values = msg->readAll();
assert(values.size() == 2);
- DBus::ObjectPathValuePtr path = DBus::ObjectPathValuePtr::dynamicCast(values[0]);
- assert(path);
+ DBus::StringValuePtr addr = DBus::StringValuePtr::dynamicCast(values[0]);
+ assert(addr);
+ VariantMap props;
+ extractProperties(values[1], props);
- InterfacePropertiesMap interfaceProps;
- extractInterfaceProperties(values[1], interfaceProps);
+ vector<DiscoveryCallbackPtr> callbacks;
- InterfacePropertiesMap::iterator p = interfaceProps.find("org.bluez.Device1");
- if(p != interfaceProps.end())
{
- //
- // A remote device was added.
- //
- deviceAdded(path->v, p->second);
- }
+ IceUtil::Monitor<IceUtil::Mutex>::Lock lock(_lock);
- p = interfaceProps.find("org.bluez.Adapter1");
- if(p != interfaceProps.end())
- {
- //
- // A local Bluetooth adapter was added.
- //
- adapterAdded(path->v, p->second);
+ map<string, vector<DiscoveryCallbackPtr> >::iterator p = _discoveryCallbacks.find(msg->getPath());
+ if(p != _discoveryCallbacks.end())
+ {
+ callbacks = p->second;
+ }
}
- return true;
- }
- else if(intf == "org.freedesktop.DBus.ObjectManager" && member == "InterfacesRemoved")
- {
- //
- // The InterfacesRemoved signal contains two values:
- //
- // OBJPATH obj_path
- // ARRAY<STRING> interfaces
- //
-
- vector<DBus::ValuePtr> values = msg->readAll();
- assert(values.size() == 2);
- DBus::ObjectPathValuePtr path = DBus::ObjectPathValuePtr::dynamicCast(values[0]);
- assert(path);
- DBus::ArrayValuePtr ifaces = DBus::ArrayValuePtr::dynamicCast(values[1]);
- assert(ifaces);
-
- for(vector<DBus::ValuePtr>::const_iterator q = ifaces->elements.begin(); q != ifaces->elements.end(); ++q)
+ if(!callbacks.empty())
{
- assert((*q)->getType()->getKind() == DBus::Type::KindString);
- DBus::StringValuePtr ifaceName = DBus::StringValuePtr::dynamicCast(*q);
-
- //
- // A remote device was removed.
- //
- if(ifaceName->v == "org.bluez.Device1")
+ PropertyMap pm; // Convert to string-string map.
+ for(VariantMap::const_iterator p = props.begin(); p != props.end(); ++p)
{
- deviceRemoved(path->v);
+ pm[p->first] = p->second->toString();
}
- else if(ifaceName->v == "org.bluez.Adapter1")
+ for(vector<DiscoveryCallbackPtr>::iterator p = callbacks.begin(); p != callbacks.end(); ++p)
{
- adapterRemoved(path->v);
+ try
+ {
+ (*p)->discovered(addr->v, pm);
+ }
+ catch(...)
+ {
+ }
}
}
return true;
}
- else if(intf == "org.freedesktop.DBus.Properties" && member == "PropertiesChanged")
+ else if(intf == "org.bluez.Adapter" && member == "PropertyChanged")
{
//
- // The PropertiesChanged signal contains three values:
+ // The PropertyChanged signal contains two values:
//
- // STRING interface_name
- // DICT<STRING,VARIANT> changed_properties
- // ARRAY<STRING> invalidated_properties
+ // STRING name
+ // VARIANT value
//
-
vector<DBus::ValuePtr> values = msg->readAll();
- assert(values.size() == 3);
- DBus::StringValuePtr iface = DBus::StringValuePtr::dynamicCast(values[0]);
- assert(iface);
-
- if(iface->v != "org.bluez.Device1" && iface->v != "org.bluez.Adapter1")
- {
- return false;
- }
-
- VariantMap changed;
- extractProperties(values[1], changed);
-
- DBus::ArrayValuePtr a = DBus::ArrayValuePtr::dynamicCast(values[2]);
- assert(a);
- vector<string> removedNames;
- for(vector<DBus::ValuePtr>::const_iterator p = a->elements.begin(); p != a->elements.end(); ++p)
- {
- DBus::StringValuePtr sv = DBus::StringValuePtr::dynamicCast(*p);
- assert(sv);
- removedNames.push_back(sv->v);
- }
+ assert(values.size() == 2);
+ DBus::StringValuePtr name = DBus::StringValuePtr::dynamicCast(values[0]);
+ assert(name);
+ if(name->v == "Discovering")
+ {
+ DBus::VariantValuePtr v = DBus::VariantValuePtr::dynamicCast(values[1]);
+ assert(v);
+ DBus::BooleanValuePtr b = DBus::BooleanValuePtr::dynamicCast(v->v);
+ assert(b);
+ if(!b->v)
+ {
+ IceUtil::Monitor<IceUtil::Mutex>::Lock lock(_lock);
- if(iface->v == "org.bluez.Device1")
- {
- deviceChanged(msg->getPath(), changed, removedNames);
- }
- else
- {
- adapterChanged(msg->getPath(), changed, removedNames);
+ map<string, vector<DiscoveryCallbackPtr> >::iterator p = _discoveryCallbacks.find(msg->getPath());
+ if(p != _discoveryCallbacks.end())
+ {
+ _discoveryCallbacks.erase(p);
+ }
+ }
}
-
- return true;
+ return false;
}
return false;
@@ -466,118 +182,131 @@ public:
string getDefaultAdapterAddress() const
{
- IceUtil::Monitor<IceUtil::Mutex>::Lock lock(_lock);
+ string path = getDefaultAdapter();
+ VariantMap props = getAdapterProperties(path);
- //
- // Return the device address of the default local adapter.
- //
- // TBD: Be smarter about this? E.g., consider the state of the Powered property?
- //
- if(!_adapters.empty())
+ VariantMap::const_iterator i = props.find("Address");
+ if(i != props.end())
{
- return _adapters.begin()->second.getAddress();
+ DBus::StringValuePtr str = DBus::StringValuePtr::dynamicCast(i->second->v);
+ assert(str);
+ return IceUtilInternal::toUpper(str->v);
}
- throw BluetoothException(__FILE__, __LINE__, "no Bluetooth adapter found");
+ throw BluetoothException(__FILE__, __LINE__, "no default Bluetooth adapter found");
}
bool adapterExists(const string& addr) const
{
- IceUtil::Monitor<IceUtil::Mutex>::Lock lock(_lock);
+ string path = findAdapter(addr);
+ return !path.empty();
+ }
- //
- // Check if a local adapter exists with the given device address.
- //
- for(AdapterMap::const_iterator p = _adapters.begin(); p != _adapters.end(); ++p)
+ unsigned int addService(const string& addr, const string& name, const string& uuid, int channel)
+ {
+ string path = findAdapter(addr);
+
+ if(path.empty())
{
- if(addr == p->second.getAddress())
- {
- return true;
- }
+ throw BluetoothException(__FILE__, __LINE__, "no Bluetooth adapter found matching address " + addr);
}
- return false;
- }
-
- //
- // Calling registerProfile will advertise a service (SDP) profile with the Bluetooth daemon.
- //
- string registerProfile(const string& uuid, const string& name, int channel, const ProfileCallbackPtr& cb)
- {
//
- // As a subclass of DBus::Service, the ServerProfile object will receive DBus method
- // invocations for a given object path.
- //
- ProfilePtr profile = new ServerProfile(cb);
-
- string path = generatePath();
+ // Compose an XML record.
+ //
+ ostringstream ostr;
+ ostr << "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" << endl
+ << "<record>" << endl
+ << " <attribute id=\"0x0001\">" << endl // UUID
+ << " <sequence>" << endl
+ << " <uuid value=\"" << uuid << "\" />" << endl
+ << " </sequence>" << endl
+ << " </attribute>" << endl
+ << " <attribute id=\"0x0004\">" << endl
+ << " <sequence>" << endl
+ << " <sequence>" << endl
+ << " <uuid value=\"0x0100\" />" << endl // L2CAP
+ << " </sequence>" << endl
+ << " <sequence>" << endl
+ << " <uuid value=\"0x0003\" />" << endl // RFCOMM channel
+ << " <uint8 value=\"0x" << hex << channel << dec << "\" />" << endl
+ << " </sequence>" << endl
+ << " </sequence>" << endl
+ << " </attribute>" << endl
+ << " <attribute id=\"0x0005\">" << endl
+ << " <sequence>" << endl
+ << " <uuid value=\"0x1002\" />" << endl
+ << " </sequence>" << endl
+ << " </attribute>" << endl;
+ if(!name.empty())
+ {
+ ostr << " <attribute id=\"0x0100\">" << endl
+ << " <text value=\"" << name << "\" />" << endl
+ << " </attribute>" << endl;
+ }
+ ostr << "</record>";
try
{
- DBus::AsyncResultPtr ar = registerProfileImpl(_dbusConnection, path, uuid, name, channel, profile);
- DBus::MessagePtr reply = ar->waitUntilFinished(); // Block until finished.
- if(reply->isError())
- {
- reply->throwException();
- }
+ DBus::MessagePtr reply = call(path, "org.bluez.Service", "AddRecord", new DBus::StringValue(ostr.str()));
+ DBus::ValuePtr v = reply->read();
+ DBus::Uint32ValuePtr handle = DBus::Uint32ValuePtr::dynamicCast(v);
+ return handle->v;
}
catch(const DBus::Exception& ex)
{
throw BluetoothException(__FILE__, __LINE__, ex.reason);
}
-
- return path;
}
- void unregisterProfile(const string& path)
+ void findService(const string& addr, const string& uuid, const FindServiceCallbackPtr& cb)
{
- try
+ IceUtil::Monitor<IceUtil::Mutex>::Lock lock(_lock);
+
+ if(_destroyed)
{
- //
- // Block while we unregister the profile.
- //
- DBus::AsyncResultPtr ar = unregisterProfileImpl(_dbusConnection, path);
- ar->waitUntilFinished();
- DBus::MessagePtr reply = ar->getReply();
- _dbusConnection->removeService(path);
- if(reply->isError())
- {
- reply->throwException();
- }
+ cb->exception(CommunicatorDestroyedException(__FILE__, __LINE__));
}
- catch(const DBus::Exception& ex)
+ else
{
- throw BluetoothException(__FILE__, __LINE__, ex.reason);
+ IceUtil::ThreadPtr t = new FindServiceThread(this, addr, uuid, cb);
+ _threads.push_back(t);
+ t->start();
}
}
- void connect(const string& addr, const string& uuid, const ConnectCallbackPtr& cb)
+ void removeService(const string& addr, unsigned int handle)
{
- IceUtil::Monitor<IceUtil::Mutex>::Lock lock(_lock);
+ string path = findAdapter(addr);
- //
- // Start a thread to establish the connection.
- //
- IceUtil::ThreadPtr t = new ConnectThread(this, addr, uuid, cb);
- _connectThreads.push_back(t);
- t->start();
+ if(path.empty())
+ {
+ throw BluetoothException(__FILE__, __LINE__, "no Bluetooth adapter found matching address " + addr);
+ }
+
+ try
+ {
+ call(path, "org.bluez.Service", "RemoveRecord", new DBus::Uint32Value(handle));
+ }
+ catch(const DBus::Exception& ex)
+ {
+ if(ex.reason.find("DoesNotExist") != string::npos)
+ {
+ throw BluetoothException(__FILE__, __LINE__, ex.reason);
+ }
+ }
}
void startDiscovery(const string& addr, const DiscoveryCallbackPtr& cb)
{
string path;
-
+ if(addr.empty())
{
- IceUtil::Monitor<IceUtil::Mutex>::Lock lock(_lock);
-
- for(AdapterMap::iterator p = _adapters.begin(); p != _adapters.end(); ++p)
- {
- if(p->second.getAddress() == IceUtilInternal::toUpper(addr))
- {
- path = p->first;
- p->second.callbacks.push_back(cb);
- }
- }
+ path = getDefaultAdapter();
+ }
+ else
+ {
+ path = findAdapter(addr);
}
if(path.empty())
@@ -585,18 +314,20 @@ public:
throw BluetoothException(__FILE__, __LINE__, "no Bluetooth adapter found matching address " + addr);
}
- //
- // Invoke StartDiscovery() on the adapter object.
- //
- try
{
- DBus::MessagePtr msg = DBus::Message::createCall("org.bluez", path, "org.bluez.Adapter1", "StartDiscovery");
- DBus::AsyncResultPtr r = _dbusConnection->callAsync(msg);
- DBus::MessagePtr reply = r->waitUntilFinished();
- if(reply->isError())
+ IceUtil::Monitor<IceUtil::Mutex>::Lock lock(_lock);
+
+ map<string, vector<DiscoveryCallbackPtr> >::iterator p = _discoveryCallbacks.find(path);
+ if(p == _discoveryCallbacks.end())
{
- reply->throwException();
+ _discoveryCallbacks[path] = vector<DiscoveryCallbackPtr>();
}
+ _discoveryCallbacks[path].push_back(cb);
+ }
+
+ try
+ {
+ call(path, "org.bluez.Adapter", "StartDiscovery");
}
catch(const DBus::Exception& ex)
{
@@ -607,18 +338,13 @@ public:
void stopDiscovery(const string& addr)
{
string path;
-
+ if(addr.empty())
{
- IceUtil::Monitor<IceUtil::Mutex>::Lock lock(_lock);
-
- for(AdapterMap::iterator p = _adapters.begin(); p != _adapters.end(); ++p)
- {
- if(p->second.getAddress() == IceUtilInternal::toUpper(addr))
- {
- path = p->first;
- p->second.callbacks.clear();
- }
- }
+ path = getDefaultAdapter();
+ }
+ else
+ {
+ path = findAdapter(addr);
}
if(path.empty())
@@ -626,18 +352,9 @@ public:
throw BluetoothException(__FILE__, __LINE__, "no Bluetooth adapter found matching address " + addr);
}
- //
- // Invoke StopDiscovery() on the adapter object.
- //
try
{
- DBus::MessagePtr msg = DBus::Message::createCall("org.bluez", path, "org.bluez.Adapter1", "StopDiscovery");
- DBus::AsyncResultPtr r = _dbusConnection->callAsync(msg);
- DBus::MessagePtr reply = r->waitUntilFinished();
- if(reply->isError())
- {
- reply->throwException();
- }
+ call(path, "org.bluez.Adapter", "StopDiscovery");
}
catch(const DBus::Exception& ex)
{
@@ -647,17 +364,16 @@ public:
void destroy()
{
- //
- // Wait for any active connect threads to finish.
- //
- vector<IceUtil::ThreadPtr> v;
+ vector<IceUtil::ThreadPtr> threads;
{
IceUtil::Monitor<IceUtil::Mutex>::Lock lock(_lock);
- v.swap(_connectThreads);
+
+ _destroyed = true;
+ threads.swap(_threads);
}
- for(vector<IceUtil::ThreadPtr>::iterator p = v.begin(); p != v.end(); ++p)
+ for(vector<IceUtil::ThreadPtr>::iterator p = threads.begin(); p != threads.end(); ++p)
{
(*p)->getThreadControl().join();
}
@@ -674,537 +390,423 @@ public:
}
}
- void getManagedObjects()
- {
- try
- {
- //
- // Query the Bluetooth service for its managed objects. This is a standard DBus invocation
- // with the following signature:
- //
- // org.freedesktop.DBus.ObjectManager.GetManagedObjects (
- // out DICT<OBJPATH,DICT<STRING,DICT<STRING,VARIANT>>> objpath_interfaces_and_properties);
- //
- DBus::MessagePtr msg =
- DBus::Message::createCall("org.bluez", "/", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
- DBus::AsyncResultPtr r = _dbusConnection->callAsync(msg);
- DBus::MessagePtr reply = r->waitUntilFinished();
- if(reply->isError())
- {
- reply->throwException();
- }
-
- IceUtil::Monitor<IceUtil::Mutex>::Lock lock(_lock);
-
- _adapters.clear();
- _remoteDevices.clear();
- _defaultAdapterAddress.clear();
-
- //
- // The return value of GetManagedObjects is a dictionary structured like this:
- //
- // Key: Object path (e.g., "/org/bluez")
- // Value: Dictionary of interfaces
- // Key: Interface name (e.g., "org.bluez.Adapter1")
- // Value: Dictionary of properties
- // Key: Property name
- // Value: Property value (variant)
- //
-
- //
- // Extract the dictionary from the reply message.
- //
- DBus::ValuePtr v = reply->read();
-
- //
- // Iterate through the dictionary and collect the objects that we need.
- //
- assert(v->getType()->getKind() == DBus::Type::KindArray);
- DBus::ArrayValuePtr a = DBus::ArrayValuePtr::dynamicCast(v);
- for(vector<DBus::ValuePtr>::const_iterator p = a->elements.begin(); p != a->elements.end(); ++p)
- {
- assert((*p)->getType()->getKind() == DBus::Type::KindDictEntry);
- DBus::DictEntryValuePtr e = DBus::DictEntryValuePtr::dynamicCast(*p);
- assert(e->key->getType()->getKind() == DBus::Type::KindObjectPath);
- DBus::ObjectPathValuePtr path = DBus::ObjectPathValuePtr::dynamicCast(e->key);
-
- assert(e->value->getType()->getKind() == DBus::Type::KindArray);
- InterfacePropertiesMap ipmap;
- extractInterfaceProperties(e->value, ipmap);
-
- InterfacePropertiesMap::iterator q;
-
- q = ipmap.find("org.bluez.Adapter1");
- if(q != ipmap.end())
- {
- //
- // org.bluez.Adapter1 is the interface for local Bluetooth adapters.
- //
- _adapters[path->v] = Adapter(q->second);
- }
-
- q = ipmap.find("org.bluez.Device1");
- if(q != ipmap.end())
- {
- //
- // org.bluez.Device1 is the interface for paired remote devices.
- //
- RemoteDevice d(q->second);
- if(!d.getAddress().empty())
- {
- _remoteDevices[path->v] = d;
- }
- }
- }
- }
- catch(const DBus::Exception& ex)
- {
- throw BluetoothException(__FILE__, __LINE__, ex.reason);
- }
- }
-
- DBus::AsyncResultPtr registerProfileImpl(const DBus::ConnectionPtr& conn, const string& path, const string& uuid,
- const string& name, int channel, const ProfilePtr& profile)
+ string getDefaultAdapter() const
{
- conn->addService(path, profile);
-
//
- // Invoke RegisterProfile on the profile manager object.
+ // The call to DefaultAdapter returns OBJ_PATH.
//
- DBus::MessagePtr msg =
- DBus::Message::createCall("org.bluez", "/org/bluez", "org.bluez.ProfileManager1", "RegisterProfile");
- vector<DBus::ValuePtr> args;
- args.push_back(new DBus::ObjectPathValue(path));
- args.push_back(new DBus::StringValue(uuid));
- DBus::DictEntryTypePtr dt =
- new DBus::DictEntryType(DBus::Type::getPrimitive(DBus::Type::KindString), new DBus::VariantType);
- DBus::TypePtr t = new DBus::ArrayType(dt);
- DBus::ArrayValuePtr options = new DBus::ArrayValue(t);
- if(!name.empty())
- {
- options->elements.push_back(
- new DBus::DictEntryValue(dt, new DBus::StringValue("Name"),
- new DBus::VariantValue(new DBus::StringValue(name))));
- }
- if(channel != -1)
- {
- options->elements.push_back(
- new DBus::DictEntryValue(dt, new DBus::StringValue("Channel"),
- new DBus::VariantValue(new DBus::Uint16Value(channel))));
- options->elements.push_back(
- new DBus::DictEntryValue(dt, new DBus::StringValue("Role"),
- new DBus::VariantValue(new DBus::StringValue("server"))));
- }
- else
- {
- options->elements.push_back(
- new DBus::DictEntryValue(dt, new DBus::StringValue("Role"),
- new DBus::VariantValue(new DBus::StringValue("client"))));
- }
- args.push_back(options);
- msg->write(args);
- return conn->callAsync(msg);
+ DBus::MessagePtr reply = call("/", "org.bluez.Manager", "DefaultAdapter");
+ DBus::ValuePtr v = reply->read();
+ DBus::ObjectPathValuePtr path = DBus::ObjectPathValuePtr::dynamicCast(v);
+ assert(path);
+ return path->v;
}
- DBus::AsyncResultPtr unregisterProfileImpl(const DBus::ConnectionPtr& conn, const string& path)
+ string findAdapter(const string& addr) const
{
//
- // Invoke UnregisterProfile on the profile manager object.
+ // The call to FindAdapter returns OBJ_PATH.
//
- DBus::MessagePtr msg =
- DBus::Message::createCall("org.bluez", "/org/bluez", "org.bluez.ProfileManager1", "UnregisterProfile");
- msg->write(new DBus::ObjectPathValue(path));
- return conn->callAsync(msg);
+ DBus::MessagePtr reply = call("/", "org.bluez.Manager", "FindAdapter", new DBus::StringValue(addr));
+ DBus::ValuePtr v = reply->read();
+ DBus::ObjectPathValuePtr path = DBus::ObjectPathValuePtr::dynamicCast(v);
+ assert(path);
+ return path->v;
}
- static string generatePath()
+ VariantMap getAdapterProperties(const string& path) const
{
//
- // Generate a unique object path. Path elements can only contain "[A-Z][a-z][0-9]_".
+ // The call to GetProperties returns
//
- string path = "/com/zeroc/P" + IceUtil::generateUUID();
- for(string::iterator p = path.begin(); p != path.end(); ++p)
- {
- if(*p == '-')
- {
- *p = '_';
- }
- }
- return path;
+ // DICT<STRING,VARIANT> properties
+ //
+ DBus::MessagePtr reply = call(path, "org.bluez.Adapter", "GetProperties");
+ DBus::ValuePtr v = reply->read();
+ VariantMap props;
+ extractProperties(v, props);
+ return props;
}
- void deviceAdded(const string& path, const VariantMap& props)
+ IceXML::NodePtr findChild(const IceXML::NodePtr& parent, const string& name) const
{
- RemoteDevice dev(props);
- if(dev.getAddress().empty())
- {
- return; // Ignore devices that don't have an Address property.
- }
-
- vector<DiscoveryCallbackPtr> callbacks;
-
+ IceXML::NodeList l = parent->getChildren();
+ for(IceXML::NodeList::iterator p = l.begin(); p != l.end(); ++p)
{
- IceUtil::Monitor<IceUtil::Mutex>::Lock lock(_lock);
-
- AdapterMap::iterator p = _adapters.find(dev.getAdapter());
- if(p != _adapters.end())
+ if((*p)->getName() == name)
{
- callbacks = p->second.callbacks;
+ return *p;
}
- _remoteDevices[path] = dev;
}
- if(!callbacks.empty())
+ return 0;
+ }
+
+ IceXML::NodePtr findAttribute(const IceXML::NodePtr& record, int id) const
+ {
+ IceXML::NodeList l = record->getChildren();
+ for(IceXML::NodeList::iterator p = l.begin(); p != l.end(); ++p)
{
- PropertyMap pm; // Convert to string-string map.
- for(VariantMap::const_iterator p = props.begin(); p != props.end(); ++p)
- {
- pm[p->first] = p->second->toString();
- }
- for(vector<DiscoveryCallbackPtr>::iterator p = callbacks.begin(); p != callbacks.end(); ++p)
+ if((*p)->getName() == "attribute")
{
- try
- {
- (*p)->discovered(dev.getAddress(), pm);
- }
- catch(...)
+ string sid = (*p)->getAttribute("id");
+ int i;
+ if(sscanf(sid.c_str(), "%x", &i) == 1 && i == id)
{
+ return *p;
}
}
}
+
+ return 0;
}
- void deviceChanged(const string& path, const VariantMap& changed, const vector<string>& removedProps)
+ IceXML::NodePtr findSequence(const IceXML::NodePtr& parent, const string& uuid) const
{
- vector<DiscoveryCallbackPtr> callbacks;
- string addr;
- string adapter;
- VariantMap props;
-
+ IceXML::NodeList l = parent->getChildren();
+ for(IceXML::NodeList::iterator p = l.begin(); p != l.end(); ++p)
{
- IceUtil::Monitor<IceUtil::Mutex>::Lock lock(_lock);
-
- RemoteDeviceMap::iterator p = _remoteDevices.find(path);
- if(p == _remoteDevices.end())
+ if((*p)->getName() == "sequence")
{
- RemoteDevice dev(changed);
- addr = dev.getAddress();
- if(!addr.empty())
+ IceXML::NodePtr u = findChild(*p, "uuid");
+ if(u)
{
- _remoteDevices[path] = dev;
- props = changed;
- adapter = dev.getAdapter();
+ string val = u->getAttribute("value");
+ if(IceUtilInternal::toUpper(val) == IceUtilInternal::toUpper(uuid))
+ {
+ return *p;
+ }
}
- }
- else
- {
- updateProperties(p->second.properties, changed, removedProps);
-
- addr = p->second.getAddress();
- if(addr.empty())
- {
- //
- // Remove the device if we don't know its address.
- //
- _remoteDevices.erase(p);
- }
- else
+ //
+ // Recursively search for nested <sequence> elements.
+ //
+ IceXML::NodePtr n = findSequence(*p, uuid);
+ if(n)
{
- props = p->second.properties;
- adapter = p->second.getAdapter();
+ return n;
}
}
-
- AdapterMap::iterator q = _adapters.find(adapter);
- if(q != _adapters.end())
- {
- callbacks = q->second.callbacks;
- }
}
- if(!addr.empty() && !callbacks.empty())
+ return 0;
+ }
+
+ IceXML::NodePtr findSequence(const IceXML::NodePtr& parent, int uuid) const
+ {
+ IceXML::NodeList l = parent->getChildren();
+ for(IceXML::NodeList::iterator p = l.begin(); p != l.end(); ++p)
{
- PropertyMap pm; // Convert to string-string map.
- for(VariantMap::iterator p = props.begin(); p != props.end(); ++p)
+ if((*p)->getName() == "sequence")
{
- pm[p->first] = p->second->toString();
- }
- for(vector<DiscoveryCallbackPtr>::iterator p = callbacks.begin(); p != callbacks.end(); ++p)
- {
- try
+ IceXML::NodePtr u = findChild(*p, "uuid");
+ if(u)
{
- (*p)->discovered(addr, pm);
+ string val = u->getAttribute("value");
+ int i;
+ if(sscanf(val.c_str(), "%x", &i) == 1 && i == uuid)
+ {
+ return *p;
+ }
}
- catch(...)
+
+ //
+ // Recursively search for nested <sequence> elements.
+ //
+ IceXML::NodePtr n = findSequence(*p, uuid);
+ if(n)
{
+ return n;
}
}
}
- }
-
- void deviceRemoved(const string& path)
- {
- IceUtil::Monitor<IceUtil::Mutex>::Lock lock(_lock);
-
- RemoteDeviceMap::iterator p = _remoteDevices.find(path);
- if(p != _remoteDevices.end())
- {
- _remoteDevices.erase(p);
- }
- }
-
- void adapterAdded(const string& path, const VariantMap& props)
- {
- IceUtil::Monitor<IceUtil::Mutex>::Lock lock(_lock);
-
- _adapters[path] = Adapter(props);
- }
-
- void adapterChanged(const string& path, const VariantMap& changed, const vector<string>& removedProps)
- {
- IceUtil::Monitor<IceUtil::Mutex>::Lock lock(_lock);
-
- AdapterMap::iterator p = _adapters.find(path);
- if(p == _adapters.end())
- {
- _adapters[path] = Adapter(changed);
- }
- else
- {
- updateProperties(p->second.properties, changed, removedProps);
- }
- }
-
- void adapterRemoved(const string& path)
- {
- IceUtil::Monitor<IceUtil::Mutex>::Lock lock(_lock);
-
- AdapterMap::iterator p = _adapters.find(path);
- if(p != _adapters.end())
- {
- _adapters.erase(p);
- }
- }
-
- void extractInterfaceProperties(const DBus::ValuePtr& v, InterfacePropertiesMap& interfaceProps)
- {
- //
- // The given value is a dictionary structured like this:
- //
- // Key: Interface name (e.g., "org.bluez.Adapter1")
- // Value: Dictionary of properties
- // Key: Property name
- // Value: Property value (variant)
- //
-
- DBus::ArrayValuePtr ifaces = DBus::ArrayValuePtr::dynamicCast(v);
- assert(ifaces);
-
- for(vector<DBus::ValuePtr>::const_iterator q = ifaces->elements.begin(); q != ifaces->elements.end(); ++q)
- {
- assert((*q)->getType()->getKind() == DBus::Type::KindDictEntry);
- DBus::DictEntryValuePtr ie = DBus::DictEntryValuePtr::dynamicCast(*q);
- assert(ie->key->getType()->getKind() == DBus::Type::KindString);
- DBus::StringValuePtr ifaceName = DBus::StringValuePtr::dynamicCast(ie->key);
-
- VariantMap pm;
- extractProperties(ie->value, pm);
-
- interfaceProps[ifaceName->v] = pm;
- }
- }
- void extractProperties(const DBus::ValuePtr& v, VariantMap& vm)
- {
- //
- // The given value is a dictionary structured like this:
- //
- // Key: Property name
- // Value: Property value (variant)
- //
-
- assert(v->getType()->getKind() == DBus::Type::KindArray);
- DBus::ArrayValuePtr props = DBus::ArrayValuePtr::dynamicCast(v);
- for(vector<DBus::ValuePtr>::const_iterator s = props->elements.begin(); s != props->elements.end(); ++s)
- {
- assert((*s)->getType()->getKind() == DBus::Type::KindDictEntry);
- DBus::DictEntryValuePtr pe = DBus::DictEntryValuePtr::dynamicCast(*s);
- assert(pe->key->getType()->getKind() == DBus::Type::KindString);
- DBus::StringValuePtr propName = DBus::StringValuePtr::dynamicCast(pe->key);
- assert(pe->value->getType()->getKind() == DBus::Type::KindVariant);
- vm[propName->v] = DBus::VariantValuePtr::dynamicCast(pe->value);
- }
+ return 0;
}
- void updateProperties(VariantMap& props, const VariantMap& changed, const vector<string>& removedProps)
+ DBus::MessagePtr call(const string& path, const string& intf, const string& member,
+ const DBus::ValuePtr& arg = 0) const
{
- //
- // Remove properties.
- //
- for(vector<string>::const_iterator q = removedProps.begin(); q != removedProps.end(); ++q)
+ DBus::MessagePtr msg = DBus::Message::createCall("org.bluez", path, intf, member);
+ if(arg)
{
- VariantMap::iterator r = props.find(*q);
- if(r != props.end())
- {
- props.erase(r);
- }
+ msg->write(arg);
}
-
- //
- // Merge changes.
- //
- for(VariantMap::const_iterator q = changed.begin(); q != changed.end(); ++q)
+ DBus::AsyncResultPtr r = _dbusConnection->callAsync(msg);
+ DBus::MessagePtr reply = r->waitUntilFinished();
+ if(reply->isError())
{
- props[q->first] = q->second;
+ reply->throwException();
}
+ return reply;
}
- void runConnectThread(const IceUtil::ThreadPtr& thread, const string& addr, const string& uuid,
- const ConnectCallbackPtr& cb)
+ void runFindService(const IceUtil::ThreadPtr& thread, const string& addr, const string& uuid,
+ const FindServiceCallbackPtr& cb)
{
- //
- // Establishing a connection is a complicated process.
- //
- // 1) Determine whether our local Bluetooth service knows about the target
- // remote device denoted by the 'addr' argument. The known remote devices
- // are included in the managed objects returned by the GetManagedObjects
- // invocation on the Bluetooth service and updated dynamically during
- // discovery.
- //
- // 2) After we find the remote device, we have to register a client profile
- // for the given UUID.
- //
- // 3) After registering the profile, we have to invoke ConnectDevice on the
- // local device object corresponding to the target address. The Bluetooth
- // service will attempt to establish a connection to the remote device.
- // If the connection succeeds, our profile object will receive a
- // NewConnection invocation that supplies the file descriptor.
- //
-
- ConnectionIPtr conn;
- bool ok = true;
+ int channel = -1;
try
{
+ const string a = IceUtilInternal::toUpper(addr);
+ const string adapter = getDefaultAdapter();
+
string devicePath;
+ bool first = true;
- //
- // Search our list of known devices for one that matches the given address.
- //
+ while(devicePath.empty())
{
- IceUtil::Monitor<IceUtil::Mutex>::Lock lock(_lock);
-
- for(RemoteDeviceMap::iterator p = _remoteDevices.begin(); p != _remoteDevices.end(); ++p)
+ try
{
- if(p->second.getAddress() == IceUtilInternal::toUpper(addr))
+ DBus::MessagePtr reply = call(adapter, "org.bluez.Adapter", "FindDevice", new DBus::StringValue(a));
+ DBus::ValuePtr v = reply->read();
+ DBus::ObjectPathValuePtr path = DBus::ObjectPathValuePtr::dynamicCast(v);
+ assert(path);
+ devicePath = path->v;
+ }
+ catch(const DBus::Exception& ex)
+ {
+ if(ex.reason.find("DoesNotExist") != string::npos)
{
- devicePath = p->first;
- break;
+ if(first)
+ {
+ first = false;
+ try
+ {
+ DBus::MessagePtr reply = call(adapter, "org.bluez.Adapter", "CreateDevice",
+ new DBus::StringValue(a));
+ DBus::ValuePtr v = reply->read();
+ DBus::ObjectPathValuePtr path = DBus::ObjectPathValuePtr::dynamicCast(v);
+ assert(path);
+ devicePath = path->v;
+ }
+ catch(const DBus::Exception&)
+ {
+ // Try FindDevice one more time.
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+ else
+ {
+ throw BluetoothException(__FILE__, __LINE__, ex.reason);
}
}
}
- //
- // If we don't find a match, we're done.
- //
if(devicePath.empty())
{
//
- // ConnectorI handles this situation specially.
+ // Couldn't get the object path for the device.
//
- throw Ice::NoEndpointException(__FILE__, __LINE__, addr);
+ throw BluetoothException(__FILE__, __LINE__, "unable to create device for address " + addr);
}
- //
- // We have a matching device, now register a client profile.
- //
- DBus::ConnectionPtr dbusConn = DBus::Connection::getSystemBus();
- conn = new ConnectionI(dbusConn, devicePath, uuid);
+ DBus::ValuePtr services;
- ProfilePtr profile = new ClientProfile(conn, cb);
- string path = generatePath();
+ for(int iter = 0; iter < 50; ++iter)
+ {
+ {
+ IceUtil::Monitor<IceUtil::Mutex>::Lock lock(_lock);
- //
- // Register a client profile. Client profiles are not advertised in SDP.
- //
- DBus::AsyncResultPtr r = registerProfileImpl(dbusConn, path, uuid, string(), -1, profile);
- DBus::MessagePtr reply = r->waitUntilFinished();
- if(reply->isError())
+ if(_destroyed)
+ {
+ throw CommunicatorDestroyedException(__FILE__, __LINE__);
+ }
+ }
+
+ try
+ {
+ //
+ // Try to call DiscoverServices on the device to get the XML service records.
+ // The return value is a DICT<UINT32, STRING>.
+ //
+ DBus::MessagePtr reply = call(devicePath, "org.bluez.Device", "DiscoverServices",
+ new DBus::StringValue(""));
+ services = reply->read();
+ break;
+ }
+ catch(const DBus::Exception& ex)
+ {
+ if(ex.reason.find("InProgress") == string::npos)
+ {
+ throw BluetoothException(__FILE__, __LINE__, ex.reason);
+ }
+
+ //
+ // Another call to DiscoverServices is already in progress for the target device.
+ // Sleep a little and try again.
+ //
+ IceUtil::ThreadControl::sleep(IceUtil::Time::milliSeconds(100));
+ }
+ }
+
+ if(!services)
{
- reply->throwException();
+ throw BluetoothException(__FILE__, __LINE__, "query for services failed for address " + addr);
}
//
- // Invoke ConnectProfile to initiate the client-side connection:
- //
- // void ConnectProfile(string uuid)
+ // The returned dictionary contains an XML record for each service advertised by the
+ // remote device. We have to parse the XML and look for certain elements. Specifically,
+ // we're looking for a UUID that matches the one supplied by the caller. If we find
+ // that, we look in the same record for an RFCOMM channel.
//
- // We only care about errors from this invocation. If the connection succeeds, our
- // client profile will receive a separate NewConnection invocation.
- //
- DBus::MessagePtr msg =
- DBus::Message::createCall("org.bluez", devicePath, "org.bluez.Device1", "ConnectProfile");
- msg->write(new DBus::StringValue(uuid));
- r = dbusConn->callAsync(msg);
- reply = r->waitUntilFinished();
- if(reply->isError())
+ IceXML::DocumentPtr doc;
+ assert(services->getType()->getKind() == DBus::Type::KindArray);
+ DBus::ArrayValuePtr d = DBus::ArrayValuePtr::dynamicCast(services);
+ for(vector<DBus::ValuePtr>::const_iterator p = d->elements.begin(); p != d->elements.end(); ++p)
{
+ assert((*p)->getType()->getKind() == DBus::Type::KindDictEntry);
+ DBus::DictEntryValuePtr pe = DBus::DictEntryValuePtr::dynamicCast(*p);
+ assert(pe->value->getType()->getKind() == DBus::Type::KindString);
+ DBus::StringValuePtr rec = DBus::StringValuePtr::dynamicCast(pe->value);
+
try
{
- reply->throwException();
+ //
+ // This is what we're processing:
+ //
+ // <record>
+ // <attribute id="0x0001">
+ // <sequence>
+ // <uuid value="f6d289b4-1596-4294-ac34-f08e8adbfe5b" />
+ // </sequence>
+ // </attribute>
+ // <attribute id="0x0004">
+ // <sequence>
+ // <sequence>
+ // <uuid value="0x0100" />
+ // </sequence>
+ // <sequence>
+ // <uuid value="0x0003" />
+ // <uint8 value="0x01" />
+ // </sequence>
+ // </sequence>
+ // </attribute>
+ // ...
+ // </record>
+ //
+
+ istringstream istr(rec->v);
+ doc = IceXML::Parser::parse(istr);
+ IceXML::NodePtr record = findChild(doc, "record");
+ if(!record)
+ {
+ throw BluetoothException(__FILE__, __LINE__, "malformed XML - can't find <record>");
+ }
+
+ //
+ // Attribute 0x0001 holds the UUID. See if it matches the target UUID.
+ //
+ IceXML::NodePtr attrib = findAttribute(record, 1);
+ IceXML::NodePtr seq;
+ if(attrib)
+ {
+ seq = findSequence(attrib, uuid);
+ }
+ if(seq)
+ {
+ //
+ // We found a matching service UUID. Now look for the RFCOMM channel in the
+ // protocol descriptor list.
+ //
+ attrib = findAttribute(record, 4);
+ if(attrib)
+ {
+ seq = findSequence(attrib, 3);
+ if(seq)
+ {
+ IceXML::NodePtr ch = findChild(seq, "uint8");
+ if(ch)
+ {
+ string val = ch->getAttribute("value");
+ if(sscanf(val.c_str(), "%x", &channel) == 1)
+ {
+ break;
+ }
+ }
+ }
+ }
+ }
}
- catch(const DBus::Exception& ex)
+ catch(const IceXML::ParserException& ex)
{
- ostringstream ostr;
- ostr << "unable to establish connection to " << uuid << " at " << addr;
- if(!ex.reason.empty())
+ if(doc)
{
- ostr << ':' << endl << ex.reason;
+ doc->destroy();
}
+ ostringstream ostr;
+ ostr << ex.reason() << endl << rec->v;
throw BluetoothException(__FILE__, __LINE__, ostr.str());
}
+ catch(...)
+ {
+ if(doc)
+ {
+ doc->destroy();
+ }
+ throw;
+ }
+ }
+
+ if(doc)
+ {
+ doc->destroy();
+ }
+
+ {
+ IceUtil::Monitor<IceUtil::Mutex>::Lock lock(_lock);
+
+ if(_destroyed)
+ {
+ throw CommunicatorDestroyedException(__FILE__, __LINE__);
+ }
}
}
catch(const DBus::Exception& ex)
{
- ok = false;
- cb->failed(BluetoothException(__FILE__, __LINE__, ex.reason));
+ cb->exception(BluetoothException(__FILE__, __LINE__, ex.reason));
}
- catch(const Ice::LocalException& ex)
+ catch(const LocalException& ex)
{
- ok = false;
- cb->failed(ex);
+ cb->exception(ex);
+ }
+ catch(const std::exception& ex)
+ {
+ cb->exception(UnknownException(__FILE__, __LINE__, ex.what()));
+ }
+ catch(...)
+ {
+ cb->exception(UnknownException(__FILE__, __LINE__, "unknown C++ exception"));
}
- //
- // Clean up.
- //
-
- if(!ok && conn)
+ if(channel != -1)
{
- conn->close();
+ cb->completed(channel);
}
- //
- // Remove the thread from the list.
- //
{
IceUtil::Monitor<IceUtil::Mutex>::Lock lock(_lock);
- vector<IceUtil::ThreadPtr>::iterator p = find(_connectThreads.begin(), _connectThreads.end(), thread);
- assert(p != _connectThreads.end());
- _connectThreads.erase(p);
+ vector<IceUtil::ThreadPtr>::iterator p = find(_threads.begin(), _threads.end(), thread);
+ if(p != _threads.end())
+ {
+ _threads.erase(p);
+ }
}
}
- class ConnectThread : public IceUtil::Thread
+ class FindServiceThread : public IceUtil::Thread
{
public:
- ConnectThread(const BluetoothServicePtr& mo, const string& addr, const string& uuid,
- const ConnectCallbackPtr& cb) :
- _mo(mo),
+ FindServiceThread(const BluetoothServicePtr& service, const string& addr, const string& uuid,
+ const FindServiceCallbackPtr& cb) :
+ _service(service),
_addr(addr),
_uuid(uuid),
_cb(cb)
@@ -1213,27 +815,20 @@ public:
virtual void run()
{
- _mo->runConnectThread(this, _addr, _uuid, _cb);
+ _service->runFindService(this, _addr, _uuid, _cb);
}
- private:
-
- BluetoothServicePtr _mo;
+ BluetoothServicePtr _service;
string _addr;
string _uuid;
- ConnectCallbackPtr _cb;
+ FindServiceCallbackPtr _cb;
};
IceUtil::Monitor<IceUtil::Mutex> _lock;
+ bool _destroyed;
DBus::ConnectionPtr _dbusConnection;
-
- AdapterMap _adapters;
- RemoteDeviceMap _remoteDevices;
- string _defaultAdapterAddress;
- vector<IceUtil::ThreadPtr> _connectThreads;
-
- bool _discovering;
- vector<DiscoveryCallbackPtr> _discoveryCallbacks;
+ vector<IceUtil::ThreadPtr> _threads;
+ map<string, vector<DiscoveryCallbackPtr> > _discoveryCallbacks;
};
}
@@ -1277,22 +872,22 @@ IceBT::Engine::adapterExists(const string& addr) const
return _service->adapterExists(addr);
}
-string
-IceBT::Engine::registerProfile(const string& uuid, const string& name, int channel, const ProfileCallbackPtr& cb)
+unsigned int
+IceBT::Engine::addService(const string& address, const string& name, const string& uuid, int channel)
{
- return _service->registerProfile(uuid, name, channel, cb);
+ return _service->addService(address, name, uuid, channel);
}
void
-IceBT::Engine::unregisterProfile(const string& path)
+IceBT::Engine::findService(const string& address, const string& uuid, const FindServiceCallbackPtr& cb)
{
- return _service->unregisterProfile(path);
+ _service->findService(address, uuid, cb);
}
void
-IceBT::Engine::connect(const string& addr, const string& uuid, const ConnectCallbackPtr& cb)
+IceBT::Engine::removeService(const string& address, unsigned int handle)
{
- _service->connect(addr, uuid, cb);
+ _service->removeService(address, handle);
}
void