summaryrefslogtreecommitdiff
path: root/cpp/src/IceBT/AcceptorI.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cpp/src/IceBT/AcceptorI.cpp')
-rw-r--r--cpp/src/IceBT/AcceptorI.cpp233
1 files changed, 233 insertions, 0 deletions
diff --git a/cpp/src/IceBT/AcceptorI.cpp b/cpp/src/IceBT/AcceptorI.cpp
new file mode 100644
index 00000000000..b561e61197b
--- /dev/null
+++ b/cpp/src/IceBT/AcceptorI.cpp
@@ -0,0 +1,233 @@
+// **********************************************************************
+//
+// 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/AcceptorI.h>
+#include <IceBT/Engine.h>
+#include <IceBT/EndpointI.h>
+#include <IceBT/Instance.h>
+#include <IceBT/TransceiverI.h>
+#include <IceBT/Util.h>
+
+#include <Ice/Communicator.h>
+#include <Ice/Exception.h>
+#include <Ice/LocalException.h>
+#include <Ice/Network.h>
+#include <Ice/Properties.h>
+#include <Ice/StreamSocket.h>
+#include <IceUtil/StringUtil.h>
+
+using namespace std;
+using namespace Ice;
+using namespace IceBT;
+
+IceUtil::Shared* IceBT::upCast(AcceptorI* p) { return p; }
+
+namespace
+{
+
+class ProfileCallbackI : public ProfileCallback
+{
+public:
+
+ ProfileCallbackI(const AcceptorIPtr& acceptor) :
+ _acceptor(acceptor)
+ {
+ }
+
+ virtual void newConnection(int fd)
+ {
+ _acceptor->newConnection(fd);
+ }
+
+private:
+
+ AcceptorIPtr _acceptor;
+};
+
+}
+
+IceInternal::NativeInfoPtr
+IceBT::AcceptorI::getNativeInfo()
+{
+ return this;
+}
+
+void
+IceBT::AcceptorI::close()
+{
+ if(!_path.empty())
+ {
+ try
+ {
+ _instance->engine()->unregisterProfile(_path);
+ }
+ catch(...)
+ {
+ }
+ }
+}
+
+IceInternal::EndpointIPtr
+IceBT::AcceptorI::listen()
+{
+ assert(!_uuid.empty());
+
+ //
+ // The Bluetooth daemon will select an available channel if _channel == 0.
+ //
+
+ try
+ {
+ _path = _instance->engine()->registerProfile(_uuid, _name, _channel, new ProfileCallbackI(this));
+ }
+ catch(const BluetoothException& ex)
+ {
+ InitializationException e(__FILE__, __LINE__);
+ e.reason = "unable to register SDP service";
+ if(!ex.reason.empty())
+ {
+ e.reason += "\n" + ex.reason;
+ }
+ throw e;
+ }
+
+ _endpoint = _endpoint->endpoint(this);
+ return _endpoint;
+}
+
+IceInternal::TransceiverPtr
+IceBT::AcceptorI::accept()
+{
+ //
+ // The plug-in may not be initialized.
+ //
+ if(!_instance->initialized())
+ {
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = "IceBT: plug-in is not initialized";
+ throw ex;
+ }
+
+ IceInternal::TransceiverPtr t;
+
+ {
+ IceUtil::Monitor<IceUtil::Mutex>::Lock lock(_lock);
+
+ //
+ // The thread pool should only call accept() when we've notified it that we have a
+ // new transceiver ready to be accepted.
+ //
+ assert(!_transceivers.empty());
+ t = _transceivers.top();
+ _transceivers.pop();
+
+ //
+ // Update our status with the thread pool.
+ //
+ ready(IceInternal::SocketOperationRead, !_transceivers.empty());
+ }
+
+ return t;
+}
+
+string
+IceBT::AcceptorI::protocol() const
+{
+ return _instance->protocol();
+}
+
+string
+IceBT::AcceptorI::toString() const
+{
+ return addrToString(_addr, _channel);
+}
+
+string
+IceBT::AcceptorI::toDetailedString() const
+{
+ ostringstream os;
+ os << "local address = " << toString();
+ if(!_name.empty())
+ {
+ os << "\nservice name = '" << _name << "'";
+ }
+ if(!_uuid.empty())
+ {
+ os << "\nservice uuid = " << _uuid;
+ }
+ return os.str();
+}
+
+int
+IceBT::AcceptorI::effectiveChannel() const
+{
+ //
+ // If no channel was specified in the endpoint (_channel == 0), the Bluetooth daemon will select
+ // an available channel for us. Unfortunately, there's no way to discover what that channel is
+ // (aside from waiting for the first incoming connection and inspecting the socket endpoint).
+ //
+
+ return _channel;
+}
+
+void
+IceBT::AcceptorI::newConnection(int fd)
+{
+ IceUtil::Monitor<IceUtil::Mutex>::Lock lock(_lock);
+
+ _transceivers.push(new TransceiverI(_instance, new StreamSocket(_instance, fd), 0, _uuid));
+
+ //
+ // Notify the thread pool that we are ready to "read". The thread pool will invoke accept()
+ // and we can return the new transceiver.
+ //
+ ready(IceInternal::SocketOperationRead, true);
+}
+
+IceBT::AcceptorI::AcceptorI(const EndpointIPtr& endpoint, const InstancePtr& instance, const string& adapterName,
+ const string& addr, const string& uuid, const string& name, int channel) :
+ _endpoint(endpoint),
+ _instance(instance),
+ _adapterName(adapterName),
+ _addr(addr),
+ _uuid(uuid),
+ _name(name),
+ _channel(channel)
+{
+ string s = IceUtilInternal::trim(_addr);
+ if(s.empty())
+ {
+ //
+ // If no address was specified, we use the first available BT adapter.
+ //
+ s = _instance->engine()->getDefaultDeviceAddress();
+ }
+
+ s = IceUtilInternal::toUpper(s);
+
+ DeviceAddress da;
+ if(!parseDeviceAddress(s, da))
+ {
+ EndpointParseException ex(__FILE__, __LINE__);
+ ex.str = "invalid address value `" + s + "' in endpoint " + endpoint->toString();
+ throw ex;
+ }
+ if(!_instance->engine()->deviceExists(s))
+ {
+ EndpointParseException ex(__FILE__, __LINE__);
+ ex.str = "no device found for `" + s + "' in endpoint " + endpoint->toString();
+ throw ex;
+ }
+
+ const_cast<string&>(_addr) = s;
+}
+
+IceBT::AcceptorI::~AcceptorI()
+{
+}