diff options
author | Benoit Foucher <benoit@zeroc.com> | 2016-06-27 17:54:30 +0200 |
---|---|---|
committer | Benoit Foucher <benoit@zeroc.com> | 2016-06-27 17:54:30 +0200 |
commit | c56f8ab6ca6ca0bdb9536fcce1ef24f1ef40ddc7 (patch) | |
tree | 5cb64dfe155e5d2349efb6c7dc4b0f5b5284d44a /cpp/src/IceIAP | |
parent | Fix Windows php build to restore nuget packages (diff) | |
download | ice-c56f8ab6ca6ca0bdb9536fcce1ef24f1ef40ddc7.tar.bz2 ice-c56f8ab6ca6ca0bdb9536fcce1ef24f1ef40ddc7.tar.xz ice-c56f8ab6ca6ca0bdb9536fcce1ef24f1ef40ddc7.zip |
Refactored SSL and iAP transports, support for running SSL on top
of TCP/iAP/Bluetooth.
Diffstat (limited to 'cpp/src/IceIAP')
-rw-r--r-- | cpp/src/IceIAP/Connector.h | 58 | ||||
-rw-r--r-- | cpp/src/IceIAP/Connector.mm | 153 | ||||
-rw-r--r-- | cpp/src/IceIAP/EndpointI.h | 110 | ||||
-rw-r--r-- | cpp/src/IceIAP/EndpointI.mm | 706 | ||||
-rw-r--r-- | cpp/src/IceIAP/Makefile.mk | 20 | ||||
-rw-r--r-- | cpp/src/IceIAP/Transceiver.h | 86 | ||||
-rw-r--r-- | cpp/src/IceIAP/Transceiver.mm | 477 |
7 files changed, 1610 insertions, 0 deletions
diff --git a/cpp/src/IceIAP/Connector.h b/cpp/src/IceIAP/Connector.h new file mode 100644 index 00000000000..f2bd4281d95 --- /dev/null +++ b/cpp/src/IceIAP/Connector.h @@ -0,0 +1,58 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 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. +// +// ********************************************************************** + +#ifndef ICE_IAP_CONNECTOR_H +#define ICE_IAP_CONNECTOR_H + +#include <Ice/TransceiverF.h> +#include <Ice/ProtocolInstanceF.h> +#include <Ice/TraceLevelsF.h> +#include <Ice/LoggerF.h> +#include <Ice/Connector.h> + +#import <Foundation/Foundation.h> +#import <ExternalAccessory/ExternalAccessory.h> + +namespace IceObjC +{ + +class iAPEndpointI; + +class Instance; +typedef IceUtil::Handle<Instance> InstancePtr; + +class iAPConnector : public IceInternal::Connector +{ +public: + + virtual IceInternal::TransceiverPtr connect(); + + virtual Ice::Short type() const; + virtual std::string toString() const; + + virtual bool operator==(const IceInternal::Connector&) const; + virtual bool operator!=(const IceInternal::Connector&) const; + virtual bool operator<(const IceInternal::Connector&) const; + +private: + + iAPConnector(const IceInternal::ProtocolInstancePtr&, Ice::Int, const std::string&, NSString*, EAAccessory*); + virtual ~iAPConnector(); + friend class iAPEndpointI; + + const IceInternal::ProtocolInstancePtr _instance; + const Ice::Int _timeout; + const std::string _connectionId; + NSString* _protocol; + EAAccessory* _accessory; +}; + +} + +#endif diff --git a/cpp/src/IceIAP/Connector.mm b/cpp/src/IceIAP/Connector.mm new file mode 100644 index 00000000000..b7c57ddb31b --- /dev/null +++ b/cpp/src/IceIAP/Connector.mm @@ -0,0 +1,153 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 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 "Transceiver.h" +#include "EndpointI.h" +#include "Connector.h" + +#include <Ice/ProtocolInstance.h> +#include <Ice/Exception.h> + +using namespace std; +using namespace Ice; +using namespace IceInternal; + +TransceiverPtr +IceObjC::iAPConnector::connect() +{ + EASession* session = [[EASession alloc] initWithAccessory:_accessory forProtocol:_protocol]; + if(!session) + { + throw Ice::ConnectFailedException(__FILE__, __LINE__, 0); + } + return new iAPTransceiver(_instance, session); +} + +Short +IceObjC::iAPConnector::type() const +{ + return _instance->type(); +} + +string +IceObjC::iAPConnector::toString() const +{ + ostringstream os; + os << [_accessory.name UTF8String]; + os << " model `" << [_accessory.modelNumber UTF8String] << "'"; + os << " made by `" << [_accessory.manufacturer UTF8String] << "'"; + os << " protocol `" << [_protocol UTF8String] << "'"; + return os.str(); +} + +bool +IceObjC::iAPConnector::operator==(const IceInternal::Connector& r) const +{ + const iAPConnector* p = dynamic_cast<const iAPConnector*>(&r); + if(!p) + { + return false; + } + + if(_timeout != p->_timeout) + { + return false; + } + + if(_connectionId != p->_connectionId) + { + return false; + } + + if(![_accessory isEqual:p->_accessory]) + { + return false; + } + + if(![_protocol isEqual:p->_protocol]) + { + return false; + } + + return true; +} + +bool +IceObjC::iAPConnector::operator!=(const IceInternal::Connector& r) const +{ + return !operator==(r); +} + +bool +IceObjC::iAPConnector::operator<(const IceInternal::Connector& r) const +{ + const iAPConnector* p = dynamic_cast<const iAPConnector*>(&r); + if(!p) + { + return type() < r.type(); + } + + if(_timeout < p->_timeout) + { + return true; + } + else if(p->_timeout < _timeout) + { + return false; + } + + if(_connectionId < p->_connectionId) + { + return true; + } + else if(p->_connectionId < _connectionId) + { + return false; + } + + if([_accessory hash] < [p->_accessory hash]) + { + return true; + } + else if([p->_accessory hash] < [_accessory hash]) + { + return false; + } + + NSInteger order = [_protocol compare:p->_protocol]; + if(order == NSOrderedAscending) + { + return true; + } + else if(order == NSOrderedDescending) + { + return false; + } + + return false; +} + +IceObjC::iAPConnector::iAPConnector(const ProtocolInstancePtr& instance, + Ice::Int timeout, + const string& connectionId, + NSString* protocol, + EAAccessory* accessory) : + _instance(instance), + _timeout(timeout), + _connectionId(connectionId), + _protocol([protocol retain]), + _accessory([accessory retain]) +{ +} + +IceObjC::iAPConnector::~iAPConnector() +{ + [_protocol release]; + [_accessory release]; +} diff --git a/cpp/src/IceIAP/EndpointI.h b/cpp/src/IceIAP/EndpointI.h new file mode 100644 index 00000000000..c4016073453 --- /dev/null +++ b/cpp/src/IceIAP/EndpointI.h @@ -0,0 +1,110 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 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. +// +// ********************************************************************** + +#ifndef ICE_IAP_ENDPOINT_I_H +#define ICE_IAP_ENDPOINT_I_H + +#include <Ice/ProtocolInstanceF.h> +#include <Ice/EndpointI.h> +#include <Ice/EndpointFactory.h> + +namespace IceObjC +{ + +class iAPEndpointI; +#ifdef ICE_CPP11_MAPPING // C++11 mapping +typedef ::std::shared_ptr<iAPEndpointI> iAPEndpointIPtr; +#else +typedef IceUtil::Handle<iAPEndpointI> iAPEndpointIPtr; +#endif + +class iAPEndpointI : public IceInternal::EndpointI, public Ice::EnableSharedFromThis<iAPEndpointI> +{ +public: + + iAPEndpointI(const IceInternal::ProtocolInstancePtr&, const std::string&, const std::string&, const std::string&, + const std::string&, Ice::Int, const std::string&, bool); + iAPEndpointI(const IceInternal::ProtocolInstancePtr&); + iAPEndpointI(const IceInternal::ProtocolInstancePtr&, Ice::InputStream*); + + virtual void streamWriteImpl(Ice::OutputStream*) const; + + virtual Ice::EndpointInfoPtr getInfo() const; + virtual Ice::Short type() const; + virtual const std::string& protocol() const; + virtual bool datagram() const; + virtual bool secure() const; + + virtual Ice::Int timeout() const; + virtual IceInternal::EndpointIPtr timeout(Ice::Int) const; + virtual const std::string& connectionId() const; + virtual IceInternal::EndpointIPtr connectionId(const std::string&) const; + virtual bool compress() const; + virtual IceInternal::EndpointIPtr compress(bool) const; + + virtual IceInternal::TransceiverPtr transceiver() const; + virtual void connectors_async(Ice::EndpointSelectionType, const IceInternal::EndpointI_connectorsPtr&) const; + virtual IceInternal::AcceptorPtr acceptor(const std::string&) const; + + virtual std::vector<IceInternal::EndpointIPtr> expand() const; + virtual bool equivalent(const IceInternal::EndpointIPtr&) const; + +#ifdef ICE_CPP11_MAPPING + virtual bool operator==(const Ice::Endpoint&) const; + virtual bool operator<(const Ice::Endpoint&) const; +#else + virtual bool operator==(const Ice::LocalObject&) const; + virtual bool operator<(const Ice::LocalObject&) const; +#endif + + virtual std::string options() const; + virtual ::Ice::Int hash() const; + +private: + + virtual bool checkOption(const std::string&, const std::string&, const std::string&); + + // + // All members are const, because endpoints are immutable. + // + const IceInternal::ProtocolInstancePtr _instance; + const std::string _manufacturer; + const std::string _modelNumber; + const std::string _name; + const std::string _protocol; + const Ice::Int _timeout; + const std::string _connectionId; + const bool _compress; +}; + +class iAPEndpointFactory : public IceInternal::EndpointFactory +{ +public: + + iAPEndpointFactory(const IceInternal::ProtocolInstancePtr&); + + virtual ~iAPEndpointFactory(); + + virtual Ice::Short type() const; + virtual std::string protocol() const; + virtual IceInternal::EndpointIPtr create(std::vector<std::string>&, bool) const; + virtual IceInternal::EndpointIPtr read(Ice::InputStream*) const; + virtual void destroy(); + + virtual IceInternal::EndpointFactoryPtr clone(const IceInternal::ProtocolInstancePtr&, + const IceInternal::EndpointFactoryPtr&) const; + +private: + + IceInternal::ProtocolInstancePtr _instance; +}; + +} + +#endif diff --git a/cpp/src/IceIAP/EndpointI.mm b/cpp/src/IceIAP/EndpointI.mm new file mode 100644 index 00000000000..44a0526d9ab --- /dev/null +++ b/cpp/src/IceIAP/EndpointI.mm @@ -0,0 +1,706 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 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 "EndpointI.h" +#include "Connector.h" + +#include <IceIAP/EndpointInfo.h> + +#include <Ice/Network.h> +#include <Ice/InputStream.h> +#include <Ice/OutputStream.h> +#include <Ice/LocalException.h> +#include <Ice/ProtocolInstance.h> +#include <Ice/DefaultsAndOverrides.h> +#include <Ice/Initialize.h> +#include <Ice/EndpointFactoryManager.h> +#include <Ice/Properties.h> +#include <Ice/HashUtil.h> +#include <Ice/ProtocolPluginFacade.h> +#include <Ice/RegisterPlugins.h> + +#include <CoreFoundation/CoreFoundation.h> + +#include <fstream> + +using namespace std; +using namespace Ice; +using namespace IceInternal; + +namespace +{ + +class iAPEndpointFactoryPlugin : public Ice::Plugin +{ +public: + + iAPEndpointFactoryPlugin(const Ice::CommunicatorPtr& com) + { + ProtocolPluginFacadePtr pluginFacade = getProtocolPluginFacade(com); + + // iAP transport + ProtocolInstancePtr instance = new ProtocolInstance(com, iAPEndpointType, "iap", false); + pluginFacade->addEndpointFactory(new IceObjC::iAPEndpointFactory(instance)); + + // SSL based on iAP transport + EndpointFactoryPtr ssl = pluginFacade->getEndpointFactory(SSLEndpointType); + if(ssl) + { + ProtocolInstancePtr sslinstance = new ProtocolInstance(com, iAPSEndpointType, "iaps", true); + pluginFacade->addEndpointFactory(ssl->clone(sslinstance, new IceObjC::iAPEndpointFactory(sslinstance))); + } + } + + virtual void initialize() {} + virtual void destroy() {} +}; + +} + +extern "C" ICE_IAP_API Plugin* +createIceIAP(const CommunicatorPtr& com, const string&, const StringSeq&) +{ + return new iAPEndpointFactoryPlugin(com); +} + +namespace Ice +{ + +ICE_IAP_API void +registerIceIAP(bool loadOnInitialize) +{ + Ice::registerPluginFactory("IceIAP", createIceIAP, loadOnInitialize); +} + +} + +// +// Objective-C function to allow Objective-C programs to register plugin. +// +extern "C" ICE_IAP_API void +ICEregisterIceIAP(bool loadOnInitialize) +{ + Ice::registerIceIAP(loadOnInitialize); +} + +IceObjC::iAPEndpointI::iAPEndpointI(const ProtocolInstancePtr& instance, const string& m, + const string& o, const string& n, const string& p, Int ti, + const string& conId, bool co) : + _instance(instance), + _manufacturer(m), + _modelNumber(o), + _name(n), + _protocol(p), + _timeout(ti), + _connectionId(conId), + _compress(co) +{ +} + +IceObjC::iAPEndpointI::iAPEndpointI(const ProtocolInstancePtr& instance) : + _instance(instance), + _timeout(-1), + _compress(false) +{ +} + +IceObjC::iAPEndpointI::iAPEndpointI(const ProtocolInstancePtr& instance, InputStream* s) : + _instance(instance), + _timeout(-1), + _compress(false) +{ + s->read(const_cast<string&>(_manufacturer), false); + s->read(const_cast<string&>(_modelNumber), false); + s->read(const_cast<string&>(_name), false); + s->read(const_cast<string&>(_protocol), false); + s->read(const_cast<Int&>(_timeout)); + s->read(const_cast<bool&>(_compress)); +} + +void +IceObjC::iAPEndpointI::streamWriteImpl(OutputStream* s) const +{ + s->write(_manufacturer, false); + s->write(_modelNumber, false); + s->write(_name, false); + s->write(_protocol, false); + s->write(_timeout); + s->write(_compress); +} + +EndpointInfoPtr +IceObjC::iAPEndpointI::getInfo() const +{ + IceIAP::EndpointInfoPtr info = ICE_MAKE_SHARED(InfoI<IceIAP::EndpointInfo>, shared_from_this()); + info->timeout = _timeout; + info->compress = _compress; + info->manufacturer = _manufacturer; + info->modelNumber = _modelNumber; + info->name = _name; + info->protocol = _protocol; + return info; +} + +Short +IceObjC::iAPEndpointI::type() const +{ + return _instance->type(); +} + +const string& +IceObjC::iAPEndpointI::protocol() const +{ + return _instance->protocol(); +} + +bool +IceObjC::iAPEndpointI::datagram() const +{ + return false; +} + +bool +IceObjC::iAPEndpointI::secure() const +{ + return _instance->secure(); +} + +Int +IceObjC::iAPEndpointI::timeout() const +{ + return _timeout; +} + +EndpointIPtr +IceObjC::iAPEndpointI::timeout(Int t) const +{ + if(t == _timeout) + { + return shared_from_this(); + } + else + { + return ICE_MAKE_SHARED(iAPEndpointI, _instance, _manufacturer, _modelNumber, _name, _protocol, t, _connectionId, + _compress); + } +} + +const string& +IceObjC::iAPEndpointI::connectionId() const +{ + return _connectionId; +} + +EndpointIPtr +IceObjC::iAPEndpointI::connectionId(const string& cId) const +{ + if(cId == _connectionId) + { + return shared_from_this(); + } + else + { + return ICE_MAKE_SHARED(iAPEndpointI, _instance, _manufacturer, _modelNumber, _name, _protocol, _timeout, cId, + _compress); + } +} + +bool +IceObjC::iAPEndpointI::compress() const +{ + return _compress; +} + +EndpointIPtr +IceObjC::iAPEndpointI::compress(bool c) const +{ + if(c == _compress) + { + return shared_from_this(); + } + else + { + return ICE_MAKE_SHARED(iAPEndpointI, _instance, _manufacturer, _modelNumber, _name, _protocol, _timeout, + _connectionId, c); + } +} + +TransceiverPtr +IceObjC::iAPEndpointI::transceiver() const +{ + return 0; +} + +void +IceObjC::iAPEndpointI::connectors_async(Ice::EndpointSelectionType selType, + const EndpointI_connectorsPtr& callback) const +{ + try + { + vector<ConnectorPtr> c; + + EAAccessoryManager* manager = [EAAccessoryManager sharedAccessoryManager]; + if(manager == nil) + { + throw Ice::ConnectFailedException(__FILE__, __LINE__, 0); + } + + NSString* protocol = _protocol.empty() ? @"com.zeroc.ice" : [[NSString alloc] initWithUTF8String:_protocol.c_str()]; + NSArray* array = [manager connectedAccessories]; + NSEnumerator* enumerator = [array objectEnumerator]; + EAAccessory* accessory = nil; + while((accessory = [enumerator nextObject])) + { + if(!accessory.connected) + { + continue; + } + if(!_manufacturer.empty() && _manufacturer != [accessory.manufacturer UTF8String]) + { + continue; + } + if(!_modelNumber.empty() && _modelNumber != [accessory.modelNumber UTF8String]) + { + continue; + } + if(!_name.empty() && _name != [accessory.name UTF8String]) + { + continue; + } + if(![accessory.protocolStrings containsObject:protocol]) + { + continue; + } + c.push_back(new iAPConnector(_instance, _timeout, _connectionId, protocol, accessory)); + } + [protocol release]; + if(c.empty()) + { + throw Ice::ConnectFailedException(__FILE__, __LINE__, 0); + } + callback->connectors(c); + } + catch(const Ice::LocalException& ex) + { + callback->exception(ex); + } +} + +AcceptorPtr +IceObjC::iAPEndpointI::acceptor(const string&) const +{ + assert(false); + return 0; +} + +vector<EndpointIPtr> +IceObjC::iAPEndpointI::expand() const +{ + vector<EndpointIPtr> endps; + endps.push_back(shared_from_this()); + return endps; +} + +bool +IceObjC::iAPEndpointI::equivalent(const EndpointIPtr& endpoint) const +{ + const iAPEndpointI* endpointI = dynamic_cast<const iAPEndpointI*>(endpoint.get()); + if(!endpointI) + { + return false; + } + return endpointI->_manufacturer == _manufacturer && + endpointI->_modelNumber == _modelNumber && + endpointI->_name == _name && + endpointI->_protocol == _protocol; +} + +bool +#ifdef ICE_CPP11_MAPPING +IceObjC::iAPEndpointI::operator==(const Ice::Endpoint& r) const +#else +IceObjC::iAPEndpointI::operator==(const Ice::LocalObject& r) const +#endif +{ + const iAPEndpointI* p = dynamic_cast<const iAPEndpointI*>(&r); + if(!p) + { + return false; + } + + if(this == p) + { + return true; + } + + if(_manufacturer != p->_manufacturer) + { + return false; + } + + if(_modelNumber != p->_modelNumber) + { + return false; + } + + if(_name != p->_name) + { + return false; + } + + if(_protocol != p->_protocol) + { + return false; + } + + if(_timeout != p->_timeout) + { + return false; + } + + if(_connectionId != p->_connectionId) + { + return false; + } + + if(_compress != p->_compress) + { + return false; + } + + return true; +} + +bool +#ifdef ICE_CPP11_MAPPING +IceObjC::iAPEndpointI::operator<(const Ice::Endpoint& r) const +#else +IceObjC::iAPEndpointI::operator<(const Ice::LocalObject& r) const +#endif +{ + const iAPEndpointI* p = dynamic_cast<const iAPEndpointI*>(&r); + if(!p) + { + const IceInternal::EndpointI* e = dynamic_cast<const IceInternal::EndpointI*>(&r); + if(!e) + { + return false; + } + return type() < e->type(); + } + + if(this == p) + { + return false; + } + + if(_manufacturer < p->_manufacturer) + { + return true; + } + else if(p->_manufacturer < _manufacturer) + { + return false; + } + + if(_modelNumber < p->_modelNumber) + { + return true; + } + else if(p->_modelNumber < _modelNumber) + { + return false; + } + + if(_name < p->_name) + { + return true; + } + else if(p->_name < _name) + { + return false; + } + + if(_protocol < p->_protocol) + { + return true; + } + else if(p->_protocol < _protocol) + { + return false; + } + + if(_timeout < p->_timeout) + { + return true; + } + else if(p->_timeout < _timeout) + { + return false; + } + + if(_connectionId < p->_connectionId) + { + return true; + } + else if(p->_connectionId < _connectionId) + { + return false; + } + + if(!_compress && p->_compress) + { + return true; + } + else if(p->_compress < _compress) + { + return false; + } + + return false; +} + +string +IceObjC::iAPEndpointI::options() const +{ + // + // WARNING: Certain features, such as proxy validation in Glacier2, + // depend on the format of proxy strings. Changes to toString() and + // methods called to generate parts of the reference string could break + // these features. Please review for all features that depend on the + // format of proxyToString() before changing this and related code. + // + ostringstream s; + if(!_manufacturer.empty()) + { + s << " -m "; + bool addQuote = _manufacturer.find(':') != string::npos; + if(addQuote) + { + s << "\""; + } + s << _manufacturer; + if(addQuote) + { + s << "\""; + } + } + + if(!_modelNumber.empty()) + { + s << " -o "; + bool addQuote = _modelNumber.find(':') != string::npos; + if(addQuote) + { + s << "\""; + } + s << _modelNumber; + if(addQuote) + { + s << "\""; + } + } + + if(!_name.empty()) + { + s << " -n "; + bool addQuote = _name.find(':') != string::npos; + if(addQuote) + { + s << "\""; + } + s << _name; + if(addQuote) + { + s << "\""; + } + } + + if(!_protocol.empty()) + { + s << " -p "; + bool addQuote = _protocol.find(':') != string::npos; + if(addQuote) + { + s << "\""; + } + s << _protocol; + if(addQuote) + { + s << "\""; + } + } + + if(_timeout != -1) + { + s << " -t " << _timeout; + } + + if(_compress) + { + s << " -z"; + } + return s.str(); +} + +Ice::Int +IceObjC::iAPEndpointI::hash() const +{ + Ice::Int h = 5381; + hashAdd(h, _manufacturer); + hashAdd(h, _modelNumber); + hashAdd(h, _name); + hashAdd(h, _protocol); + hashAdd(h, _timeout); + hashAdd(h, _connectionId); + return h; +} + +bool +IceObjC::iAPEndpointI::checkOption(const string& option, const string& argument, const string& endpoint) +{ + switch(option[1]) + { + case 'm': + { + if(argument.empty()) + { + EndpointParseException ex(__FILE__, __LINE__); + ex.str = "no argument provided for -h option in endpoint " + endpoint; + throw ex; + } + const_cast<string&>(_manufacturer) = argument; + break; + } + + case 'o': + { + if(argument.empty()) + { + EndpointParseException ex(__FILE__, __LINE__); + ex.str = "no argument provided for -h option in endpoint " + endpoint; + throw ex; + } + const_cast<string&>(_modelNumber) = argument; + break; + } + + case 'n': + { + if(argument.empty()) + { + EndpointParseException ex(__FILE__, __LINE__); + ex.str = "no argument provided for -h option in endpoint " + endpoint; + throw ex; + } + const_cast<string&>(_name) = argument; + break; + } + + case 'p': + { + if(argument.empty()) + { + EndpointParseException ex(__FILE__, __LINE__); + ex.str = "no argument provided for -h option in endpoint " + endpoint; + throw ex; + } + const_cast<string&>(_protocol) = argument; + break; + } + + case 't': + { + if(argument == "infinite") + { + const_cast<Int&>(_timeout) = -1; + } + else + { + istringstream t(argument); + if(!(t >> const_cast<Int&>(_timeout)) || !t.eof() || _timeout < 1) + { + EndpointParseException ex(__FILE__, __LINE__); + ex.str = "invalid timeout value `" + argument + "' in endpoint " + endpoint; + throw ex; + } + } + break; + } + + case 'z': + { + if(!argument.empty()) + { + EndpointParseException ex(__FILE__, __LINE__); + ex.str = "no argument provided for -h option in endpoint " + endpoint; + throw ex; + } + const_cast<bool&>(_compress) = true; + break; + } + + default: + { + return false; + } + } + return true; +} + +IceObjC::iAPEndpointFactory::iAPEndpointFactory(const ProtocolInstancePtr& instance) : + _instance(instance) +{ +} + +IceObjC::iAPEndpointFactory::~iAPEndpointFactory() +{ +} + +Short +IceObjC::iAPEndpointFactory::type() const +{ + return _instance->type(); +} + +string +IceObjC::iAPEndpointFactory::protocol() const +{ + return _instance->protocol(); +} + +EndpointIPtr +IceObjC::iAPEndpointFactory::create(vector<string>& args, bool oaEndpoint) const +{ + if(oaEndpoint) + { + return 0; + } + EndpointIPtr endpt = ICE_MAKE_SHARED(iAPEndpointI, _instance); + endpt->initWithOptions(args); + return endpt; +} + +EndpointIPtr +IceObjC::iAPEndpointFactory::read(InputStream* s) const +{ + return ICE_MAKE_SHARED(iAPEndpointI, _instance, s); +} + +void +IceObjC::iAPEndpointFactory::destroy() +{ + _instance = 0; +} + +EndpointFactoryPtr +IceObjC::iAPEndpointFactory::clone(const ProtocolInstancePtr& instance, const IceInternal::EndpointFactoryPtr&) const +{ + return new iAPEndpointFactory(instance); +} diff --git a/cpp/src/IceIAP/Makefile.mk b/cpp/src/IceIAP/Makefile.mk new file mode 100644 index 00000000000..daeffbead19 --- /dev/null +++ b/cpp/src/IceIAP/Makefile.mk @@ -0,0 +1,20 @@ +# ********************************************************************** +# +# Copyright (c) 2003-2016 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. +# +# ********************************************************************** + +$(project)_libraries = IceIAP + +IceIAP_configs := xcodesdk cpp11-xcodesdk +IceIAP_platforms := iphoneos iphonesimulator + +IceIAP_targetdir := $(libdir) +IceIAP_dependencies := Ice +IceIAP_sliceflags := --include-dir IceIAP --dll-export ICE_IAP_API +IceIAP_cppflags := -DICE_IAP_API_EXPORTS + +projects += $(project) diff --git a/cpp/src/IceIAP/Transceiver.h b/cpp/src/IceIAP/Transceiver.h new file mode 100644 index 00000000000..b82ed27c395 --- /dev/null +++ b/cpp/src/IceIAP/Transceiver.h @@ -0,0 +1,86 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 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. +// +// ********************************************************************** + +#ifndef ICE_IAP_TRANSCEIVER_H +#define ICE_IAP_TRANSCEIVER_H + +#include <Ice/ProtocolInstanceF.h> +#include <Ice/Transceiver.h> +#include <Ice/Network.h> +#include <Ice/Selector.h> + +#import <Foundation/Foundation.h> +#import <ExternalAccessory/ExternalAccessory.h> + +@class iAPTransceiverCallback; + +namespace IceObjC +{ + +class iAPTransceiver : public IceInternal::Transceiver, public IceInternal::StreamNativeInfo +{ + enum State + { + StateNeedConnect, + StateConnectPending, + StateConnected + }; + +public: + + iAPTransceiver(const IceInternal::ProtocolInstancePtr&, EASession*); + virtual ~iAPTransceiver(); + + virtual void initStreams(IceInternal::SelectorReadyCallback*); + virtual IceInternal::SocketOperation registerWithRunLoop(IceInternal::SocketOperation); + virtual IceInternal::SocketOperation unregisterFromRunLoop(IceInternal::SocketOperation, bool); + virtual void closeStreams(); + + virtual IceInternal::NativeInfoPtr getNativeInfo(); + + virtual IceInternal::SocketOperation initialize(IceInternal::Buffer&, IceInternal::Buffer&); +#ifdef ICE_CPP11_MAPPING + virtual IceInternal::SocketOperation closing(bool, std::exception_ptr); +#else + virtual IceInternal::SocketOperation closing(bool, const Ice::LocalException&); +#endif + virtual void close(); + virtual IceInternal::SocketOperation write(IceInternal::Buffer&); + virtual IceInternal::SocketOperation read(IceInternal::Buffer&); + + virtual std::string protocol() const; + virtual std::string toString() const; + virtual std::string toDetailedString() const; + virtual Ice::ConnectionInfoPtr getInfo() const; + virtual void checkSendSize(const IceInternal::Buffer&); + virtual void setBufferSize(int, int); + +private: + + void checkError(NSError*, const char*, int); + + IceInternal::ProtocolInstancePtr _instance; + EASession* _session; + NSInputStream* _readStream; + NSOutputStream* _writeStream; + iAPTransceiverCallback* _callback; + bool _readStreamRegistered; + bool _writeStreamRegistered; + bool _opening; + + IceUtil::Mutex _mutex; + bool _error; + + State _state; + std::string _desc; +}; + +} + +#endif diff --git a/cpp/src/IceIAP/Transceiver.mm b/cpp/src/IceIAP/Transceiver.mm new file mode 100644 index 00000000000..a9a57dbf407 --- /dev/null +++ b/cpp/src/IceIAP/Transceiver.mm @@ -0,0 +1,477 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 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 "Transceiver.h" +#include "EndpointI.h" + +#include <IceIAP/ConnectionInfo.h> + +#include <Ice/LocalException.h> +#include <Ice/ProtocolInstance.h> +#include <Ice/Buffer.h> + +#import <Foundation/NSRunLoop.h> +#import <Foundation/NSError.h> +#import <Foundation/NSString.h> + +using namespace std; +using namespace Ice; +using namespace IceInternal; + +@interface iAPTransceiverCallback : NSObject<NSStreamDelegate> +{ +@private + + SelectorReadyCallback* callback; +} +-(id) init:(SelectorReadyCallback*)cb; +@end + +@implementation iAPTransceiverCallback +-(id) init:(SelectorReadyCallback*)cb; +{ + if(![super init]) + { + return nil; + } + callback = cb; + return self; +} + +- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode +{ + switch(eventCode) + { + case NSStreamEventHasBytesAvailable: + callback->readyCallback(SocketOperationRead); + break; + case NSStreamEventHasSpaceAvailable: + callback->readyCallback(SocketOperationWrite); + break; + case NSStreamEventOpenCompleted: + if([[stream class] isSubclassOfClass:[NSInputStream class]]) + { + callback->readyCallback(static_cast<SocketOperation>(SocketOperationConnect | SocketOperationRead)); + } + else + { + callback->readyCallback(static_cast<SocketOperation>(SocketOperationConnect | SocketOperationWrite)); + } + break; + default: + if([[stream class] isSubclassOfClass:[NSInputStream class]]) + { + callback->readyCallback(SocketOperationRead, -1); // Error + } + else + { + callback->readyCallback(SocketOperationWrite, -1); // Error + } + } +} +@end + +void +IceObjC::iAPTransceiver::initStreams(SelectorReadyCallback* callback) +{ + _callback = [[iAPTransceiverCallback alloc] init:callback]; + [_writeStream setDelegate:_callback]; + [_readStream setDelegate:_callback]; +} + +SocketOperation +IceObjC::iAPTransceiver::registerWithRunLoop(SocketOperation op) +{ + IceUtil::Mutex::Lock sync(_mutex); + SocketOperation readyOp = SocketOperationNone; + if(op & SocketOperationConnect) + { + if([_writeStream streamStatus] != NSStreamStatusNotOpen || [_readStream streamStatus] != NSStreamStatusNotOpen) + { + return SocketOperationConnect; + } + + _opening = true; + + [_writeStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; + [_readStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; + + _writeStreamRegistered = true; // Note: this must be set after the schedule call + _readStreamRegistered = true; // Note: this must be set after the schedule call + + [_writeStream open]; + [_readStream open]; + } + else + { + if(op & SocketOperationWrite) + { + if([_writeStream hasSpaceAvailable]) + { + readyOp = static_cast<SocketOperation>(readyOp | SocketOperationWrite); + } + else if(!_writeStreamRegistered) + { + [_writeStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; + _writeStreamRegistered = true; // Note: this must be set after the schedule call + if([_writeStream hasSpaceAvailable]) + { + readyOp = static_cast<SocketOperation>(readyOp | SocketOperationWrite); + } + } + } + + if(op & SocketOperationRead) + { + if([_readStream hasBytesAvailable]) + { + readyOp = static_cast<SocketOperation>(readyOp | SocketOperationRead); + } + else if(!_readStreamRegistered) + { + [_readStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; + _readStreamRegistered = true; // Note: this must be set after the schedule call + if([_readStream hasBytesAvailable]) + { + readyOp = static_cast<SocketOperation>(readyOp | SocketOperationRead); + } + } + } + } + return readyOp; +} + +SocketOperation +IceObjC::iAPTransceiver::unregisterFromRunLoop(SocketOperation op, bool error) +{ + IceUtil::Mutex::Lock sync(_mutex); + _error |= error; + + if(_opening) + { + // Wait for the stream to be ready for write + if(op == SocketOperationWrite) + { + _writeStreamRegistered = false; + } + + // + // We don't wait for the stream to be ready for read (even if + // it's a client connection) because there's no guarantees that + // the server might actually send data right away. If we use + // the WebSocket transport, the server actually waits for the + // client to write the HTTP upgrade request. + // + //if(op & SocketOperationRead && (_fd != INVALID_SOCKET || !(op & SocketOperationConnect))) + if(op == (SocketOperationRead | SocketOperationConnect)) + { + _readStreamRegistered = false; + } + + if(error || (!_readStreamRegistered && !_writeStreamRegistered)) + { + [_writeStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; + [_readStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; + _opening = false; + return SocketOperationConnect; + } + else + { + return SocketOperationNone; + } + } + else + { + if(op & SocketOperationWrite && _writeStreamRegistered) + { + [_writeStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; + _writeStreamRegistered = false; + } + + if(op & SocketOperationRead && _readStreamRegistered) + { + [_readStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; + _readStreamRegistered = false; + } + } + return op; +} + +void +IceObjC::iAPTransceiver::closeStreams() +{ + [_writeStream setDelegate:nil]; + [_readStream setDelegate:nil]; + + [_callback release]; + _callback = 0; + + [_writeStream close]; + [_readStream close]; +} + +IceInternal::NativeInfoPtr +IceObjC::iAPTransceiver::getNativeInfo() +{ + return this; +} + +SocketOperation +IceObjC::iAPTransceiver::initialize(Buffer& readBuffer, Buffer& writeBuffer) +{ + IceUtil::Mutex::Lock sync(_mutex); + if(_state == StateNeedConnect) + { + _state = StateConnectPending; + return SocketOperationConnect; + } + + if(_state <= StateConnectPending) + { + if(_error) + { + NSError* err = nil; + if([_writeStream streamStatus] == NSStreamStatusError) + { + err = [_writeStream streamError]; + } + if([_readStream streamStatus] == NSStreamStatusError) + { + err = [_readStream streamError]; + } + checkError(err, __FILE__, __LINE__); + } + _state = StateConnected; + } + assert(_state == StateConnected); + return SocketOperationNone; +} + +SocketOperation +#ifdef ICE_CPP11_MAPPING +IceObjC::iAPTransceiver::closing(bool initiator, exception_ptr) +#else +IceObjC::iAPTransceiver::closing(bool initiator, const Ice::LocalException&) +#endif +{ + // If we are initiating the connection closure, wait for the peer + // to close the TCP/IP connection. Otherwise, close immediately. + return initiator ? SocketOperationRead : SocketOperationNone; +} + +void +IceObjC::iAPTransceiver::close() +{ +} + +SocketOperation +IceObjC::iAPTransceiver::write(Buffer& buf) +{ + IceUtil::Mutex::Lock sync(_mutex); + if(_error) + { + assert([_writeStream streamStatus] == NSStreamStatusError); + checkError([_writeStream streamError], __FILE__, __LINE__); + } + + // Its impossible for the packetSize to be more than an Int. + int packetSize = static_cast<int>(buf.b.end() - buf.i); + while(buf.i != buf.b.end()) + { + if(![_writeStream hasSpaceAvailable]) + { + return SocketOperationWrite; + } + assert([_writeStream streamStatus] >= NSStreamStatusOpen); + + NSInteger ret = [_writeStream write:reinterpret_cast<const UInt8*>(&*buf.i) maxLength:packetSize]; + if(ret == SOCKET_ERROR) + { + if([_writeStream streamStatus] == NSStreamStatusAtEnd) + { + ConnectionLostException ex(__FILE__, __LINE__); + ex.error = getSocketErrno(); + throw ex; + } + + assert([_writeStream streamStatus] == NSStreamStatusError); + checkError([_writeStream streamError], __FILE__, __LINE__); + if(noBuffers() && packetSize > 1024) + { + packetSize /= 2; + } + continue; + } + + buf.i += ret; + + if(packetSize > buf.b.end() - buf.i) + { + packetSize = static_cast<int>(buf.b.end() - buf.i); + } + } + + return SocketOperationNone; +} + +SocketOperation +IceObjC::iAPTransceiver::read(Buffer& buf) +{ + IceUtil::Mutex::Lock sync(_mutex); + if(_error) + { + assert([_readStream streamStatus] == NSStreamStatusError); + checkError([_readStream streamError], __FILE__, __LINE__); + } + + // Its impossible for the packetSize to be more than an Int. + int packetSize = static_cast<int>(buf.b.end() - buf.i); + while(buf.i != buf.b.end()) + { + if(![_readStream hasBytesAvailable] && [_readStream streamStatus] != NSStreamStatusError) + { + return SocketOperationRead; + } + assert([_readStream streamStatus] >= NSStreamStatusOpen); + + NSInteger ret = [_readStream read:reinterpret_cast<UInt8*>(&*buf.i) maxLength:packetSize]; + if(ret == 0) + { + ConnectionLostException ex(__FILE__, __LINE__); + ex.error = 0; + throw ex; + } + + if(ret == SOCKET_ERROR) + { + if([_readStream streamStatus] == NSStreamStatusAtEnd) + { + ConnectionLostException ex(__FILE__, __LINE__); + ex.error = getSocketErrno(); + throw ex; + } + + assert([_readStream streamStatus] == NSStreamStatusError); + checkError([_readStream streamError], __FILE__, __LINE__); + if(noBuffers() && packetSize > 1024) + { + packetSize /= 2; + } + continue; + } + + buf.i += ret; + + if(packetSize > buf.b.end() - buf.i) + { + packetSize = static_cast<int>(buf.b.end() - buf.i); + } + } + + return SocketOperationNone; +} + +string +IceObjC::iAPTransceiver::protocol() const +{ + return _instance->protocol(); +} + +string +IceObjC::iAPTransceiver::toString() const +{ + return _desc; +} + +string +IceObjC::iAPTransceiver::toDetailedString() const +{ + return toString(); +} + +Ice::ConnectionInfoPtr +IceObjC::iAPTransceiver::getInfo() const +{ + IceIAP::ConnectionInfoPtr info = new IceIAP::ConnectionInfo(); + info->manufacturer = [_session.accessory.manufacturer UTF8String]; + info->name = [_session.accessory.name UTF8String]; + info->modelNumber = [_session.accessory.modelNumber UTF8String]; + info->firmwareRevision = [_session.accessory.firmwareRevision UTF8String]; + info->hardwareRevision = [_session.accessory.hardwareRevision UTF8String]; + info->protocol = [_session.protocolString UTF8String]; + return info; +} + +void +IceObjC::iAPTransceiver::checkSendSize(const Buffer& buf) +{ +} + +void +IceObjC::iAPTransceiver::setBufferSize(int, int) +{ +} + +IceObjC::iAPTransceiver::iAPTransceiver(const ProtocolInstancePtr& instance, EASession* session) : + StreamNativeInfo(INVALID_SOCKET), + _instance(instance), + _session([session retain]), + _readStream([session inputStream]), + _writeStream([session outputStream]), + _readStreamRegistered(false), + _writeStreamRegistered(false), + _error(false), + _state(StateNeedConnect) +{ + ostringstream os; + os << "name = " << [session.accessory.name UTF8String] << "\n"; + os << "protocol = " << [session.protocolString UTF8String]; + _desc = os.str(); +} + +IceObjC::iAPTransceiver::~iAPTransceiver() +{ + [_session release]; +} + +void +IceObjC::iAPTransceiver::checkError(NSError* err, const char* file, int line) +{ + NSString* domain = [err domain]; + if([domain compare:NSPOSIXErrorDomain] == NSOrderedSame) + { + errno = [err code]; + [err release]; + if(connectionRefused()) + { + ConnectionRefusedException ex(file, line); + ex.error = getSocketErrno(); + throw ex; + } + else if(connectFailed()) + { + ConnectFailedException ex(file, line); + ex.error = getSocketErrno(); + throw ex; + } + else + { + SocketException ex(file, line); + ex.error = getSocketErrno(); + throw ex; + } + } + + // Otherwise throw a generic exception. + CFNetworkException ex(file, line); + ex.domain = [domain UTF8String]; + ex.error = [err code]; + [err release]; + throw ex; +} |