summaryrefslogtreecommitdiff
path: root/cpp/src/IceBT/Engine.cpp
diff options
context:
space:
mode:
authorMark Spruiell <mes@zeroc.com>2015-11-06 11:24:22 -0800
committerMark Spruiell <mes@zeroc.com>2015-11-06 11:24:22 -0800
commit61f9f44b8eda9c9cdb9139436d4ad87e6e7d5839 (patch)
tree286025a254ce57d02068551f11cf69b89fa66a72 /cpp/src/IceBT/Engine.cpp
parentA few changes to support move of Freeze (diff)
downloadice-61f9f44b8eda9c9cdb9139436d4ad87e6e7d5839.tar.bz2
ice-61f9f44b8eda9c9cdb9139436d4ad87e6e7d5839.tar.xz
ice-61f9f44b8eda9c9cdb9139436d4ad87e6e7d5839.zip
initial commit of C++ Bluetooth transport
Diffstat (limited to 'cpp/src/IceBT/Engine.cpp')
-rw-r--r--cpp/src/IceBT/Engine.cpp831
1 files changed, 831 insertions, 0 deletions
diff --git a/cpp/src/IceBT/Engine.cpp b/cpp/src/IceBT/Engine.cpp
new file mode 100644
index 00000000000..293056c120d
--- /dev/null
+++ b/cpp/src/IceBT/Engine.cpp
@@ -0,0 +1,831 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+#include <IceBT/Engine.h>
+#include <IceBT/DBus.h>
+#include <IceBT/Util.h>
+#include <Ice/LocalException.h>
+#include <IceUtil/StringUtil.h>
+#include <IceUtil/Thread.h>
+#include <IceUtil/UUID.h>
+
+#include <stack>
+
+using namespace std;
+using namespace Ice;
+using namespace IceBT;
+
+IceUtil::Shared* IceBT::upCast(IceBT::Engine* p) { return p; }
+
+namespace IceBT
+{
+
+class ConnectionI;
+typedef IceUtil::Handle<ConnectionI> ConnectionIPtr;
+
+//
+// ConnectionI implements IceBT::Connection and encapsulates a DBus connection along with
+// some additional state.
+//
+class ConnectionI : public Connection
+{
+public:
+
+ ConnectionI(const DBus::ConnectionPtr& conn, const string& devicePath, const string& uuid) :
+ _connection(conn),
+ _devicePath(devicePath),
+ _uuid(uuid)
+ {
+ }
+
+ DBus::ConnectionPtr dbusConnection() const
+ {
+ return _connection;
+ }
+
+ //
+ // Blocking close.
+ //
+ 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)
+ {
+ //
+ // The callback assumes ownership of the file descriptor and connection.
+ //
+ _callback->completed(fd, _connection);
+ _connection = 0; // Remove circular reference.
+ _callback = 0;
+ }
+
+private:
+
+ ConnectionPtr _connection;
+ ConnectCallbackPtr _callback;
+};
+typedef IceUtil::Handle<ClientProfile> ClientProfilePtr;
+
+//
+// ServerProfile represents an incoming connection profile.
+//
+class ServerProfile : public Profile
+{
+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 ManagedObjects. It encapsulates a snapshot of the "objects" managed by the
+// DBus Bluetooth daemon. These objects include local Bluetooth adapters, paired devices, etc.
+//
+class ManagedObjects : public IceUtil::Shared
+{
+public:
+
+ ManagedObjects()
+ {
+ DBus::initThreads();
+
+ try
+ {
+ //
+ // Block while we establish a DBus connection and retrieve a snapshot of the managed objects
+ // from the Bluetooth service.
+ //
+ _dbusConnection = DBus::Connection::getSystemBus();
+ getManagedObjects();
+ }
+ catch(const DBus::Exception& ex)
+ {
+ throw BluetoothException(__FILE__, __LINE__, ex.reason);
+ }
+ }
+
+ string getDefaultDeviceAddress() const
+ {
+ IceUtil::Monitor<IceUtil::Mutex>::Lock lock(_lock);
+
+ //
+ // Return the device address of the default local adapter.
+ //
+
+ if(_defaultAdapterAddress.empty())
+ {
+ throw BluetoothException(__FILE__, __LINE__, "no Bluetooth adapter found");
+ }
+
+ return _defaultAdapterAddress;
+ }
+
+ bool deviceExists(const string& addr) const
+ {
+ IceUtil::Monitor<IceUtil::Mutex>::Lock lock(_lock);
+
+ //
+ // Check if a local adapter exists with the given device address.
+ //
+ for(ObjectMap::const_iterator p = _adapters.begin(); p != _adapters.end(); ++p)
+ {
+ PropertyMap::const_iterator q = p->second.find("Address");
+ if(q != p->second.end())
+ {
+ DBus::StringValuePtr str = DBus::StringValuePtr::dynamicCast(q->second->v);
+ assert(str);
+ if(addr == str->v)
+ {
+ return true;
+ }
+ }
+ }
+
+ 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();
+
+ try
+ {
+ DBus::AsyncResultPtr ar = registerProfileImpl(_dbusConnection, path, uuid, name, channel, profile);
+ DBus::MessagePtr reply = ar->waitUntilFinished(); // Block until finished.
+ if(reply->isError())
+ {
+ reply->throwException();
+ }
+ }
+ catch(const DBus::Exception& ex)
+ {
+ throw BluetoothException(__FILE__, __LINE__, ex.reason);
+ }
+
+ return path;
+ }
+
+ void unregisterProfile(const string& path)
+ {
+ try
+ {
+ //
+ // 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();
+ }
+ }
+ catch(const DBus::Exception& ex)
+ {
+ throw BluetoothException(__FILE__, __LINE__, ex.reason);
+ }
+ }
+
+ void connect(const string& addr, const string& uuid, const ConnectCallbackPtr& cb)
+ {
+ IceUtil::Monitor<IceUtil::Mutex>::Lock lock(_lock);
+
+ //
+ // Start a thread to establish the connection.
+ //
+ IceUtil::ThreadPtr t = new ConnectThread(this, addr, uuid, cb);
+ _connectThreads.push_back(t);
+ t->start();
+ }
+
+ void destroy()
+ {
+ //
+ // Wait for any active connect threads to finish.
+ //
+ vector<IceUtil::ThreadPtr> v;
+
+ {
+ IceUtil::Monitor<IceUtil::Mutex>::Lock lock(_lock);
+ v.swap(_connectThreads);
+ }
+
+ for(vector<IceUtil::ThreadPtr>::iterator p = v.begin(); p != v.end(); ++p)
+ {
+ (*p)->getThreadControl().join();
+ }
+
+ if(_dbusConnection)
+ {
+ try
+ {
+ _dbusConnection->close();
+ }
+ catch(const DBus::Exception& ex)
+ {
+ }
+ }
+ }
+
+ 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);
+ DBus::ArrayValuePtr ifaces = DBus::ArrayValuePtr::dynamicCast(e->value);
+ 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);
+
+ PropertyMap propertyMap;
+ assert(ie->value->getType()->getKind() == DBus::Type::KindArray);
+ DBus::ArrayValuePtr props = DBus::ArrayValuePtr::dynamicCast(ie->value);
+ 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);
+ propertyMap[propName->v] = DBus::VariantValuePtr::dynamicCast(pe->value);
+ }
+
+ if(ifaceName->v == "org.bluez.Adapter1")
+ {
+ //
+ // org.bluez.Adapter1 is the interface for local Bluetooth adapters.
+ //
+
+ _adapters[path->v] = propertyMap;
+
+ //
+ // Save the address of the first adapter we encounter as our "default" adapter.
+ //
+ if(_defaultAdapterAddress.empty())
+ {
+ PropertyMap::iterator t = propertyMap.find("Address");
+ if(t != propertyMap.end())
+ {
+ DBus::StringValuePtr str = DBus::StringValuePtr::dynamicCast(t->second->v);
+ assert(str);
+ if(!str->v.empty())
+ {
+ _defaultAdapterAddress = str->v;
+ }
+ }
+ }
+ }
+ else if(ifaceName->v == "org.bluez.Device1")
+ {
+ //
+ // org.bluez.Device1 is the interface for paired devices.
+ //
+
+ PropertyMap::iterator t = propertyMap.find("Address");
+ if(t != propertyMap.end())
+ {
+ DBus::StringValuePtr str = DBus::StringValuePtr::dynamicCast(t->second->v);
+ assert(str);
+ if(!str->v.empty())
+ {
+ _remoteDevices[IceUtilInternal::toUpper(str->v)] = path->v;
+ }
+ }
+ }
+ }
+ }
+ }
+ 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)
+ {
+ conn->addService(path, profile);
+
+ //
+ // Invoke RegisterProfile on the profile manager object.
+ //
+ 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::AsyncResultPtr unregisterProfileImpl(const DBus::ConnectionPtr& conn, const string& path)
+ {
+ //
+ // Invoke UnregisterProfile on the profile manager object.
+ //
+ DBus::MessagePtr msg =
+ DBus::Message::createCall("org.bluez", "/org/bluez", "org.bluez.ProfileManager1", "UnregisterProfile");
+ msg->write(new DBus::ObjectPathValue(path));
+ return conn->callAsync(msg);
+ }
+
+ static string generatePath()
+ {
+ //
+ // Generate a unique object path. Path elements can only contain "[A-Z][a-z][0-9]_".
+ //
+ string path = "/com/zeroc/P" + IceUtil::generateUUID();
+ for(string::iterator p = path.begin(); p != path.end(); ++p)
+ {
+ if(*p == '-')
+ {
+ *p = '_';
+ }
+ }
+ return path;
+ }
+
+ void runConnectThread(const IceUtil::ThreadPtr& thread, const string& addr, const string& uuid,
+ const ConnectCallbackPtr& 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.
+ //
+ // 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;
+
+ try
+ {
+ //
+ // Block while we refresh the list of known devices.
+ //
+ getManagedObjects();
+
+ string devicePath;
+
+ //
+ // Search our list of known devices for one that matches the given address.
+ //
+ {
+ IceUtil::Monitor<IceUtil::Mutex>::Lock lock(_lock);
+
+ DeviceMap::iterator p = _remoteDevices.find(IceUtilInternal::toUpper(addr));
+ if(p != _remoteDevices.end())
+ {
+ devicePath = p->second;
+ }
+ }
+
+ //
+ // If we don't find a match, we're done.
+ //
+ if(devicePath.empty())
+ {
+ //
+ // ConnectorI handles this situation specially.
+ //
+ throw Ice::NoEndpointException(__FILE__, __LINE__, addr);
+ }
+
+ //
+ // We have a matching device, now register a client profile.
+ //
+ DBus::ConnectionPtr dbusConn = DBus::Connection::getSystemBus();
+ conn = new ConnectionI(dbusConn, devicePath, uuid);
+
+ ProfilePtr profile = new ClientProfile(conn, cb);
+ string path = generatePath();
+
+ //
+ // 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())
+ {
+ reply->throwException();
+ }
+
+ //
+ // Invoke ConnectProfile to initiate the client-side connection:
+ //
+ // void ConnectProfile(string uuid)
+ //
+ // 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())
+ {
+ try
+ {
+ reply->throwException();
+ }
+ catch(const DBus::Exception& ex)
+ {
+ ostringstream ostr;
+ ostr << "unable to establish connection to " << uuid << " at " << addr;
+ if(!ex.reason.empty())
+ {
+ ostr << ':' << endl << ex.reason;
+ }
+ throw BluetoothException(__FILE__, __LINE__, ostr.str());
+ }
+ }
+ }
+ catch(const DBus::Exception& ex)
+ {
+ ok = false;
+ cb->failed(BluetoothException(__FILE__, __LINE__, ex.reason));
+ }
+ catch(const Ice::LocalException& ex)
+ {
+ ok = false;
+ cb->failed(ex);
+ }
+
+ //
+ // Clean up.
+ //
+
+ if(!ok && conn)
+ {
+ conn->close();
+ }
+
+ //
+ // 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);
+ }
+ }
+
+ class ConnectThread : public IceUtil::Thread
+ {
+ public:
+
+ ConnectThread(const ManagedObjectsPtr& mo, const string& addr, const string& uuid,
+ const ConnectCallbackPtr& cb) :
+ _mo(mo),
+ _addr(addr),
+ _uuid(uuid),
+ _cb(cb)
+ {
+ }
+
+ virtual void run()
+ {
+ _mo->runConnectThread(this, _addr, _uuid, _cb);
+ }
+
+ private:
+
+ ManagedObjectsPtr _mo;
+ string _addr;
+ string _uuid;
+ ConnectCallbackPtr _cb;
+ };
+
+ IceUtil::Monitor<IceUtil::Mutex> _lock;
+ DBus::ConnectionPtr _dbusConnection;
+
+ typedef map<string, DBus::VariantValuePtr> PropertyMap;
+ typedef map<string, PropertyMap> ObjectMap;
+ typedef map<string, string> DeviceMap; // Maps device address to object path.
+
+ ObjectMap _adapters;
+ DeviceMap _remoteDevices;
+ string _defaultAdapterAddress;
+ vector<IceUtil::ThreadPtr> _connectThreads;
+};
+
+}
+
+IceUtil::Shared* IceBT::upCast(IceBT::ManagedObjects* p) { return p; }
+
+IceBT::Engine::Engine(const Ice::CommunicatorPtr& communicator) :
+ _communicator(communicator),
+ _initialized(false)
+{
+}
+
+Ice::CommunicatorPtr
+IceBT::Engine::communicator() const
+{
+ return _communicator;
+}
+
+void
+IceBT::Engine::initialize()
+{
+ _managedObjects = new ManagedObjects;
+ _initialized = true;
+}
+
+bool
+IceBT::Engine::initialized() const
+{
+ return _initialized;
+}
+
+string
+IceBT::Engine::getDefaultDeviceAddress() const
+{
+ return _managedObjects->getDefaultDeviceAddress();
+}
+
+bool
+IceBT::Engine::deviceExists(const string& addr) const
+{
+ return _managedObjects->deviceExists(addr);
+}
+
+string
+IceBT::Engine::registerProfile(const string& uuid, const string& name, int channel, const ProfileCallbackPtr& cb)
+{
+ return _managedObjects->registerProfile(uuid, name, channel, cb);
+}
+
+void
+IceBT::Engine::unregisterProfile(const string& path)
+{
+ return _managedObjects->unregisterProfile(path);
+}
+
+void
+IceBT::Engine::connect(const string& addr, const string& uuid, const ConnectCallbackPtr& cb)
+{
+ _managedObjects->connect(addr, uuid, cb);
+}
+
+void
+IceBT::Engine::destroy()
+{
+ _managedObjects->destroy();
+}