// // Copyright (c) ZeroC, Inc. All rights reserved. // #include #include #include #include #include #include #include #include #include #include #include #include #include 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 { ProfileCallbackPtr cb = ICE_MAKE_SHARED(ProfileCallbackI, this); _path = _instance->engine()->registerProfile(_uuid, _name, _channel, cb); } catch(const BluetoothException& ex) { ostringstream os; os << "unable to register Bluetooth profile"; if(!ex.reason.empty()) { os << "\n" << ex.reason; } throw InitializationException(__FILE__, __LINE__, os.str()); } _endpoint = _endpoint->endpoint(this); return _endpoint; } IceInternal::TransceiverPtr IceBT::AcceptorI::accept() { // // The plug-in may not be initialized. // if(!_instance->initialized()) { throw PluginInitializationException(__FILE__, __LINE__, "IceBT: plug-in is not initialized"); } IceInternal::TransceiverPtr t; { IceUtil::Monitor::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::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()->getDefaultAdapterAddress(); } s = IceUtilInternal::toUpper(s); DeviceAddress da; if(!parseDeviceAddress(s, da)) { throw EndpointParseException(__FILE__, __LINE__, "invalid address value `" + s + "' in endpoint " + endpoint->toString()); } if(!_instance->engine()->adapterExists(s)) { throw EndpointParseException(__FILE__, __LINE__, "no device found for `" + s + "' in endpoint " + endpoint->toString()); } const_cast(_addr) = s; } IceBT::AcceptorI::~AcceptorI() { }