summaryrefslogtreecommitdiff
path: root/cpp/src/IceIAP
diff options
context:
space:
mode:
authorBenoit Foucher <benoit@zeroc.com>2016-06-27 17:54:30 +0200
committerBenoit Foucher <benoit@zeroc.com>2016-06-27 17:54:30 +0200
commitc56f8ab6ca6ca0bdb9536fcce1ef24f1ef40ddc7 (patch)
tree5cb64dfe155e5d2349efb6c7dc4b0f5b5284d44a /cpp/src/IceIAP
parentFix Windows php build to restore nuget packages (diff)
downloadice-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.h58
-rw-r--r--cpp/src/IceIAP/Connector.mm153
-rw-r--r--cpp/src/IceIAP/EndpointI.h110
-rw-r--r--cpp/src/IceIAP/EndpointI.mm706
-rw-r--r--cpp/src/IceIAP/Makefile.mk20
-rw-r--r--cpp/src/IceIAP/Transceiver.h86
-rw-r--r--cpp/src/IceIAP/Transceiver.mm477
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;
+}