1 // **********************************************************************
3 // Copyright (c) 2003-2011 ZeroC, Inc. All rights reserved.
5 // This copy of Ice is licensed to you under the terms described in the
6 // ICE_LICENSE file included in this distribution.
8 // **********************************************************************
10 #include <Communicator.h>
12 #include <Properties.h>
15 #include <IceUtil/Options.h>
16 #include <IceUtil/MutexPtrLock.h>
17 #include <IceUtil/StringUtil.h>
18 #include <IceUtil/Timer.h>
21 using namespace IcePHP
;
23 ZEND_EXTERN_MODULE_GLOBALS(ice
)
26 // Class entries represent the PHP class implementations we have registered.
31 zend_class_entry
* communicatorClassEntry
= 0;
34 // An active communicator is in use by at least one request and may have
35 // registered so that it remains active after a request completes. The
36 // communicator is destroyed when there are no more references to this
39 class ActiveCommunicator
: public IceUtil::Shared
43 ActiveCommunicator(const Ice::CommunicatorPtr
& c
);
44 ~ActiveCommunicator();
46 const Ice::CommunicatorPtr communicator
;
49 IceUtil::Time lastAccess
;
51 typedef IceUtil::Handle
<ActiveCommunicator
> ActiveCommunicatorPtr
;
53 typedef std::map
<std::string
, zval
*> ObjectFactoryMap
;
55 class CommunicatorInfoI
: public CommunicatorInfo
59 CommunicatorInfoI(const ActiveCommunicatorPtr
&, zval
*);
61 virtual void getZval(zval
* TSRMLS_DC
);
62 virtual void addRef(TSRMLS_D
);
63 virtual void decRef(TSRMLS_D
);
65 virtual Ice::CommunicatorPtr
getCommunicator() const;
67 bool addObjectFactory(const std::string
&, zval
* TSRMLS_DC
);
68 bool findObjectFactory(const std::string
&, zval
* TSRMLS_DC
);
69 void destroyObjectFactories(TSRMLS_D
);
71 const ActiveCommunicatorPtr ac
;
73 ObjectFactoryMap objectFactories
;
75 typedef IceUtil::Handle
<CommunicatorInfoI
> CommunicatorInfoIPtr
;
78 // Each PHP request has its own set of object factories. More precisely, there is
79 // an object factory map for each communicator that is created by a PHP request.
80 // The factory class defined below delegates the create/destroy methods to PHP
81 // objects supplied by the application. An instance of this class is installed
82 // as the communicator's default object factory, and the class holds a reference
83 // to its communicator. When create is invoked, the class resolves the appropriate
84 // PHP object as follows:
86 // * Using its communicator reference as the key, look up the corresponding
87 // CommunicatorInfoI object in the request-specific communicator map.
89 // * In the object factory map held by the CommunicatorInfoI object, look for a
90 // PHP factory object using the same algorithm as the Ice core.
92 class ObjectFactoryI
: public Ice::ObjectFactory
96 ObjectFactoryI(const Ice::CommunicatorPtr
&);
98 virtual Ice::ObjectPtr
create(const std::string
&);
99 virtual void destroy();
103 Ice::CommunicatorPtr _communicator
;
106 class ReaperTask
: public IceUtil::TimerTask
110 virtual void runTimerTask();
118 // Communicator support.
120 zend_object_handlers _handlers
;
123 // The profile map holds Properties objects corresponding to the "default" profile
124 // (defined via the ice.config & ice.options settings in php.ini) as well as named
125 // profiles defined in an external file.
127 typedef map
<string
, Ice::PropertiesPtr
> ProfileMap
;
128 ProfileMap _profiles
;
129 const string _defaultProfileName
= "";
132 // This map represents communicators that have been registered so that they can be used
133 // by multiple PHP requests.
135 typedef map
<string
, ActiveCommunicatorPtr
> RegisteredCommunicatorMap
;
136 RegisteredCommunicatorMap _registeredCommunicators
;
137 IceUtil::Mutex
* _registeredCommunicatorsMutex
= 0;
139 IceUtil::TimerPtr _timer
;
142 // This map is stored in the "global" variables for each PHP request and holds
143 // the communicators that have been created (or registered communicators that have
144 // been used) by the request.
146 typedef map
<Ice::CommunicatorPtr
, CommunicatorInfoIPtr
> CommunicatorMap
;
154 _registeredCommunicatorsMutex
= new IceUtil::Mutex();
159 delete _registeredCommunicatorsMutex
;
160 _registeredCommunicatorsMutex
= 0;
169 static zend_object_value
handleAlloc(zend_class_entry
* TSRMLS_DC
);
170 static void handleFreeStorage(void* TSRMLS_DC
);
171 static zend_object_value
handleClone(zval
* TSRMLS_DC
);
174 ZEND_METHOD(Ice_Communicator
, __construct
)
176 runtimeError("communicators cannot be instantiated directly" TSRMLS_CC
);
179 ZEND_METHOD(Ice_Communicator
, destroy
)
181 CommunicatorInfoIPtr _this
= Wrapper
<CommunicatorInfoIPtr
>::value(getThis() TSRMLS_CC
);
185 // Remove all registrations.
188 IceUtilInternal::MutexPtrLock
<IceUtil::Mutex
> lock(_registeredCommunicatorsMutex
);
189 for(vector
<string
>::iterator p
= _this
->ac
->ids
.begin(); p
!= _this
->ac
->ids
.end(); ++p
)
191 _registeredCommunicators
.erase(*p
);
193 _this
->ac
->ids
.clear();
197 // We need to destroy any object factories installed by this request.
199 _this
->destroyObjectFactories(TSRMLS_C
);
201 Ice::CommunicatorPtr c
= _this
->getCommunicator();
203 CommunicatorMap
* m
= reinterpret_cast<CommunicatorMap
*>(ICE_G(communicatorMap
));
205 assert(m
->find(c
) != m
->end());
212 catch(const IceUtil::Exception
& ex
)
214 throwException(ex TSRMLS_CC
);
219 ZEND_METHOD(Ice_Communicator
, stringToProxy
)
221 CommunicatorInfoIPtr _this
= Wrapper
<CommunicatorInfoIPtr
>::value(getThis() TSRMLS_CC
);
226 if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, const_cast<char*>("s"), &str
, &strLen
) != SUCCESS
)
230 string
s(str
, strLen
);
234 Ice::ObjectPrx prx
= _this
->getCommunicator()->stringToProxy(s
);
235 if(!createProxy(return_value
, prx
, _this TSRMLS_CC
))
240 catch(const IceUtil::Exception
& ex
)
242 throwException(ex TSRMLS_CC
);
247 ZEND_METHOD(Ice_Communicator
, proxyToString
)
249 CommunicatorInfoIPtr _this
= Wrapper
<CommunicatorInfoIPtr
>::value(getThis() TSRMLS_CC
);
253 if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, const_cast<char*>("O!"), &zv
, proxyClassEntry
) != SUCCESS
)
265 if(!fetchProxy(zv
, prx
, info TSRMLS_CC
))
270 str
= prx
->ice_toString();
272 RETURN_STRINGL(STRCAST(str
.c_str()), str
.length(), 1);
274 catch(const IceUtil::Exception
& ex
)
276 throwException(ex TSRMLS_CC
);
281 ZEND_METHOD(Ice_Communicator
, propertyToProxy
)
283 CommunicatorInfoIPtr _this
= Wrapper
<CommunicatorInfoIPtr
>::value(getThis() TSRMLS_CC
);
288 if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, const_cast<char*>("s"), &str
, &strLen
) != SUCCESS
)
292 string
s(str
, strLen
);
296 Ice::ObjectPrx prx
= _this
->getCommunicator()->propertyToProxy(s
);
297 if(!createProxy(return_value
, prx
, _this TSRMLS_CC
))
302 catch(const IceUtil::Exception
& ex
)
304 throwException(ex TSRMLS_CC
);
309 ZEND_METHOD(Ice_Communicator
, proxyToProperty
)
311 CommunicatorInfoIPtr _this
= Wrapper
<CommunicatorInfoIPtr
>::value(getThis() TSRMLS_CC
);
317 if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, const_cast<char*>("O!s"), &zv
, proxyClassEntry
, &str
, &strLen
)
323 string
prefix(str
, strLen
);
331 if(!fetchProxy(zv
, prx
, info TSRMLS_CC
))
337 Ice::PropertyDict val
= _this
->getCommunicator()->proxyToProperty(prx
, prefix
);
338 if(!createStringMap(return_value
, val TSRMLS_CC
))
345 array_init(return_value
);
348 catch(const IceUtil::Exception
& ex
)
350 throwException(ex TSRMLS_CC
);
355 ZEND_METHOD(Ice_Communicator
, stringToIdentity
)
357 CommunicatorInfoIPtr _this
= Wrapper
<CommunicatorInfoIPtr
>::value(getThis() TSRMLS_CC
);
362 if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, const_cast<char*>("s"), &str
, &strLen
) != SUCCESS
)
366 string
s(str
, strLen
);
370 Ice::Identity id
= _this
->getCommunicator()->stringToIdentity(s
);
371 if(!createIdentity(return_value
, id TSRMLS_CC
))
376 catch(const IceUtil::Exception
& ex
)
378 throwException(ex TSRMLS_CC
);
383 ZEND_METHOD(Ice_Communicator
, identityToString
)
385 CommunicatorInfoIPtr _this
= Wrapper
<CommunicatorInfoIPtr
>::value(getThis() TSRMLS_CC
);
388 zend_class_entry
* identityClass
= idToClass("::Ice::Identity" TSRMLS_CC
);
389 assert(identityClass
);
392 if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, const_cast<char*>("O"), &zv
, identityClass
) != SUCCESS
)
397 if(!extractIdentity(zv
, id TSRMLS_CC
))
404 string str
= _this
->getCommunicator()->identityToString(id
);
405 RETURN_STRINGL(STRCAST(str
.c_str()), str
.length(), 1);
407 catch(const IceUtil::Exception
& ex
)
409 throwException(ex TSRMLS_CC
);
414 ZEND_METHOD(Ice_Communicator
, addObjectFactory
)
416 CommunicatorInfoIPtr _this
= Wrapper
<CommunicatorInfoIPtr
>::value(getThis() TSRMLS_CC
);
419 zend_class_entry
* factoryClass
= idToClass("Ice::ObjectFactory" TSRMLS_CC
);
420 assert(factoryClass
);
425 if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, const_cast<char*>("Os!"), &factory
, factoryClass
, &id
,
426 &idLen TSRMLS_CC
) != SUCCESS
)
434 type
= string(id
, idLen
);
437 if(!_this
->addObjectFactory(type
, factory TSRMLS_CC
))
443 ZEND_METHOD(Ice_Communicator
, findObjectFactory
)
445 CommunicatorInfoIPtr _this
= Wrapper
<CommunicatorInfoIPtr
>::value(getThis() TSRMLS_CC
);
450 if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, const_cast<char*>("s!"), &id
, &idLen TSRMLS_CC
) != SUCCESS
)
458 type
= string(id
, idLen
);
461 if(!_this
->findObjectFactory(type
, return_value TSRMLS_CC
))
467 ZEND_METHOD(Ice_Communicator
, getImplicitContext
)
469 runtimeError("not implemented" TSRMLS_CC
);
472 ZEND_METHOD(Ice_Communicator
, getProperties
)
474 if(ZEND_NUM_ARGS() > 0)
479 CommunicatorInfoIPtr _this
= Wrapper
<CommunicatorInfoIPtr
>::value(getThis() TSRMLS_CC
);
484 Ice::PropertiesPtr props
= _this
->getCommunicator()->getProperties();
485 if(!createProperties(return_value
, props TSRMLS_CC
))
490 catch(const IceUtil::Exception
& ex
)
492 throwException(ex TSRMLS_CC
);
497 ZEND_METHOD(Ice_Communicator
, getLogger
)
499 CommunicatorInfoIPtr _this
= Wrapper
<CommunicatorInfoIPtr
>::value(getThis() TSRMLS_CC
);
504 Ice::LoggerPtr logger
= _this
->getCommunicator()->getLogger();
505 if(!createLogger(return_value
, logger TSRMLS_CC
))
510 catch(const IceUtil::Exception
& ex
)
512 throwException(ex TSRMLS_CC
);
517 ZEND_METHOD(Ice_Communicator
, getDefaultRouter
)
519 if(ZEND_NUM_ARGS() > 0)
524 CommunicatorInfoIPtr _this
= Wrapper
<CommunicatorInfoIPtr
>::value(getThis() TSRMLS_CC
);
529 Ice::RouterPrx router
= _this
->getCommunicator()->getDefaultRouter();
532 ClassInfoPtr info
= getClassInfoById("::Ice::Router" TSRMLS_CC
);
535 runtimeError("no definition for Ice::Router" TSRMLS_CC
);
538 if(!createProxy(return_value
, router
, info
, _this TSRMLS_CC
))
548 catch(const IceUtil::Exception
& ex
)
550 throwException(ex TSRMLS_CC
);
555 ZEND_METHOD(Ice_Communicator
, setDefaultRouter
)
557 CommunicatorInfoIPtr _this
= Wrapper
<CommunicatorInfoIPtr
>::value(getThis() TSRMLS_CC
);
561 if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, const_cast<char*>("O!"), &zv
, proxyClassEntry TSRMLS_CC
) !=
567 Ice::ObjectPrx proxy
;
569 if(zv
&& !fetchProxy(zv
, proxy
, info TSRMLS_CC
))
576 Ice::RouterPrx router
;
579 if(!info
|| !info
->isA("::Ice::Router"))
581 invalidArgument("setDefaultRouter requires a proxy narrowed to Ice::Router" TSRMLS_CC
);
584 router
= Ice::RouterPrx::uncheckedCast(proxy
);
586 _this
->getCommunicator()->setDefaultRouter(router
);
588 catch(const IceUtil::Exception
& ex
)
590 throwException(ex TSRMLS_CC
);
595 ZEND_METHOD(Ice_Communicator
, getDefaultLocator
)
597 if(ZEND_NUM_ARGS() > 0)
602 CommunicatorInfoIPtr _this
= Wrapper
<CommunicatorInfoIPtr
>::value(getThis() TSRMLS_CC
);
607 Ice::LocatorPrx locator
= _this
->getCommunicator()->getDefaultLocator();
610 ClassInfoPtr info
= getClassInfoById("::Ice::Locator" TSRMLS_CC
);
613 runtimeError("no definition for Ice::Locator" TSRMLS_CC
);
616 if(!createProxy(return_value
, locator
, info
, _this TSRMLS_CC
))
626 catch(const IceUtil::Exception
& ex
)
628 throwException(ex TSRMLS_CC
);
633 ZEND_METHOD(Ice_Communicator
, setDefaultLocator
)
635 CommunicatorInfoIPtr _this
= Wrapper
<CommunicatorInfoIPtr
>::value(getThis() TSRMLS_CC
);
639 if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, const_cast<char*>("O!"), &zv
, proxyClassEntry TSRMLS_CC
) !=
645 Ice::ObjectPrx proxy
;
647 if(zv
&& !fetchProxy(zv
, proxy
, info TSRMLS_CC
))
654 Ice::LocatorPrx locator
;
657 if(!info
|| !info
->isA("::Ice::Locator"))
659 invalidArgument("setDefaultLocator requires a proxy narrowed to Ice::Locator" TSRMLS_CC
);
662 locator
= Ice::LocatorPrx::uncheckedCast(proxy
);
664 _this
->getCommunicator()->setDefaultLocator(locator
);
666 catch(const IceUtil::Exception
& ex
)
668 throwException(ex TSRMLS_CC
);
673 ZEND_METHOD(Ice_Communicator
, flushBatchRequests
)
675 CommunicatorInfoIPtr _this
= Wrapper
<CommunicatorInfoIPtr
>::value(getThis() TSRMLS_CC
);
678 if(ZEND_NUM_ARGS() != 8)
685 _this
->getCommunicator()->flushBatchRequests();
687 catch(const IceUtil::Exception
& ex
)
689 throwException(ex TSRMLS_CC
);
697 static zend_object_value
698 handleAlloc(zend_class_entry
* ce TSRMLS_DC
)
700 zend_object_value result
;
702 Wrapper
<CommunicatorInfoIPtr
>* obj
= Wrapper
<CommunicatorInfoIPtr
>::create(ce TSRMLS_CC
);
705 result
.handle
= zend_objects_store_put(obj
, 0, (zend_objects_free_object_storage_t
)handleFreeStorage
, 0 TSRMLS_CC
);
706 result
.handlers
= &_handlers
;
715 handleFreeStorage(void* p TSRMLS_DC
)
717 Wrapper
<CommunicatorInfoIPtr
>* obj
= static_cast<Wrapper
<CommunicatorInfoIPtr
>*>(p
);
719 zend_objects_free_object_storage(static_cast<zend_object
*>(p
) TSRMLS_CC
);
725 static zend_object_value
726 handleClone(zval
* zv TSRMLS_DC
)
728 php_error_docref(0 TSRMLS_CC
, E_ERROR
, "communicators cannot be cloned");
729 return zend_object_value();
732 static CommunicatorInfoIPtr
733 createCommunicator(zval
* zv
, const ActiveCommunicatorPtr
& ac TSRMLS_DC
)
737 if(object_init_ex(zv
, communicatorClassEntry
) != SUCCESS
)
739 runtimeError("unable to initialize communicator object" TSRMLS_CC
);
743 Wrapper
<CommunicatorInfoIPtr
>* obj
= Wrapper
<CommunicatorInfoIPtr
>::extract(zv TSRMLS_CC
);
746 CommunicatorInfoIPtr info
= new CommunicatorInfoI(ac
, zv
);
747 obj
->ptr
= new CommunicatorInfoIPtr(info
);
750 if(ICE_G(communicatorMap
))
752 m
= reinterpret_cast<CommunicatorMap
*>(ICE_G(communicatorMap
));
756 m
= new CommunicatorMap
;
757 ICE_G(communicatorMap
) = m
;
759 m
->insert(CommunicatorMap::value_type(ac
->communicator
, info
));
763 catch(const IceUtil::Exception
& ex
)
765 throwException(ex TSRMLS_CC
);
770 static CommunicatorInfoIPtr
771 initializeCommunicator(zval
* zv
, Ice::StringSeq
& args
, bool hasArgs
, const Ice::InitializationData
& initData TSRMLS_DC
)
775 Ice::CommunicatorPtr c
;
778 c
= Ice::initialize(args
, initData
);
782 c
= Ice::initialize(initData
);
785 ActiveCommunicatorPtr ac
= new ActiveCommunicator(c
);
788 // Install a default object factory that delegates to PHP factories.
790 c
->addObjectFactory(new ObjectFactoryI(c
), "");
792 CommunicatorInfoIPtr info
= createCommunicator(zv
, ac TSRMLS_CC
);
806 catch(const IceUtil::Exception
& ex
)
808 throwException(ex TSRMLS_CC
);
813 ZEND_FUNCTION(Ice_initialize
)
815 if(ZEND_NUM_ARGS() > 2)
817 runtimeError("too many arguments" TSRMLS_CC
);
821 zend_class_entry
* initClass
= idToClass("::Ice::InitializationData" TSRMLS_CC
);
825 // Retrieve the arguments.
827 zval
*** args
= static_cast<zval
***>(emalloc(ZEND_NUM_ARGS() * sizeof(zval
**)));
828 AutoEfree
autoArgs(args
); // Call efree on return
829 if(zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args
) == FAILURE
)
831 runtimeError("unable to get arguments" TSRMLS_CC
);
836 Ice::InitializationData initData
;
840 // Accept the following invocations:
842 // initialize(array, InitializationData)
844 // initialize(InitializationData)
847 bool hasArgs
= false;
850 if(Z_TYPE_PP(args
[0]) == IS_ARRAY
)
852 if(!extractStringArray(*args
[0], seq TSRMLS_CC
))
857 if(ZEND_NUM_ARGS() > 1)
859 if(Z_TYPE_PP(args
[1]) != IS_OBJECT
|| Z_OBJCE_PP(args
[1]) != initClass
)
861 string s
= zendTypeToString(Z_TYPE_PP(args
[1]));
862 invalidArgument("expected InitializationData object but received %s" TSRMLS_CC
, s
.c_str());
868 else if(Z_TYPE_PP(args
[0]) == IS_OBJECT
&& Z_OBJCE_PP(args
[0]) == initClass
)
870 if(ZEND_NUM_ARGS() > 1)
872 runtimeError("too many arguments" TSRMLS_CC
);
879 string s
= zendTypeToString(Z_TYPE_PP(args
[0]));
880 invalidArgument("unexpected argument type %s" TSRMLS_CC
, s
.c_str());
890 member
= "properties";
891 if(zend_hash_find(Z_OBJPROP_P(zvinit
), STRCAST(member
.c_str()), member
.size() + 1, &data
) == SUCCESS
)
893 zval
** val
= reinterpret_cast<zval
**>(data
);
894 if(!fetchProperties(*val
, initData
.properties TSRMLS_CC
))
901 if(zend_hash_find(Z_OBJPROP_P(zvinit
), STRCAST(member
.c_str()), member
.size() + 1, &data
) == SUCCESS
)
903 zval
** val
= reinterpret_cast<zval
**>(data
);
904 if(!fetchLogger(*val
, initData
.logger TSRMLS_CC
))
911 CommunicatorInfoIPtr info
= initializeCommunicator(return_value
, seq
, hasArgs
, initData TSRMLS_CC
);
918 ZEND_FUNCTION(Ice_register
)
924 if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, const_cast<char*>("Os|l"), &comm
, communicatorClassEntry
, &s
,
925 &sLen
, &expires TSRMLS_CC
) != SUCCESS
)
933 invalidArgument("communicator id cannot be empty" TSRMLS_CC
);
937 CommunicatorInfoIPtr info
= Wrapper
<CommunicatorInfoIPtr
>::value(comm TSRMLS_CC
);
940 IceUtilInternal::MutexPtrLock
<IceUtil::Mutex
> lock(_registeredCommunicatorsMutex
);
942 RegisteredCommunicatorMap::iterator p
= _registeredCommunicators
.find(id
);
943 if(p
!= _registeredCommunicators
.end())
945 if(p
->second
->communicator
!= info
->getCommunicator())
948 // A different communicator is already registered with that ID.
955 info
->ac
->ids
.push_back(id
);
956 _registeredCommunicators
[id
] = info
->ac
;
962 // Update the expiration time. If a communicator is registered with multiple IDs, we
963 // always use the most recent expiration setting.
965 info
->ac
->expires
= static_cast<int>(expires
);
966 info
->ac
->lastAccess
= IceUtil::Time::now();
969 // Start the timer if necessary. Reap expired communicators every five minutes.
973 _timer
= new IceUtil::Timer
;
974 _timer
->scheduleRepeated(new ReaperTask
, IceUtil::Time::seconds(5 * 60));
981 ZEND_FUNCTION(Ice_unregister
)
985 if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, const_cast<char*>("s"), &s
, &sLen TSRMLS_CC
) != SUCCESS
)
992 IceUtilInternal::MutexPtrLock
<IceUtil::Mutex
> lock(_registeredCommunicatorsMutex
);
994 RegisteredCommunicatorMap::iterator p
= _registeredCommunicators
.find(id
);
995 if(p
== _registeredCommunicators
.end())
998 // No communicator registered with that ID.
1004 // Remove the ID from the ActiveCommunicator's list of registered IDs.
1006 ActiveCommunicatorPtr ac
= p
->second
;
1007 vector
<string
>::iterator q
= find(ac
->ids
.begin(), ac
->ids
.end(), id
);
1008 assert(q
!= ac
->ids
.end());
1011 _registeredCommunicators
.erase(p
);
1016 ZEND_FUNCTION(Ice_find
)
1020 if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, const_cast<char*>("s"), &s
, &sLen TSRMLS_CC
) != SUCCESS
)
1027 IceUtilInternal::MutexPtrLock
<IceUtil::Mutex
> lock(_registeredCommunicatorsMutex
);
1029 RegisteredCommunicatorMap::iterator p
= _registeredCommunicators
.find(id
);
1030 if(p
== _registeredCommunicators
.end())
1033 // No communicator registered with that ID.
1038 if(p
->second
->expires
> 0)
1040 p
->second
->lastAccess
= IceUtil::Time::now();
1044 // Check if this communicator has already been obtained by the current request.
1045 // If so, we can return the existing PHP object that corresponds to the communicator.
1047 CommunicatorMap
* m
= reinterpret_cast<CommunicatorMap
*>(ICE_G(communicatorMap
));
1050 CommunicatorMap::iterator q
= m
->find(p
->second
->communicator
);
1053 q
->second
->getZval(return_value TSRMLS_CC
);
1058 if(!createCommunicator(return_value
, p
->second TSRMLS_CC
))
1064 ZEND_FUNCTION(Ice_getProperties
)
1068 if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, const_cast<char*>("|s"), &s
, &sLen TSRMLS_CC
) != SUCCESS
)
1076 name
= string(s
, sLen
);
1079 ProfileMap::iterator p
= _profiles
.find(name
);
1080 if(p
== _profiles
.end())
1085 Ice::PropertiesPtr clone
= p
->second
->clone();
1086 if(!createProperties(return_value
, clone TSRMLS_CC
))
1093 // Predefined methods for Communicator.
1095 static function_entry _interfaceMethods
[] =
1099 static function_entry _classMethods
[] =
1101 ZEND_ME(Ice_Communicator
, __construct
, NULL
, ZEND_ACC_PRIVATE
|ZEND_ACC_CTOR
)
1102 ZEND_ME(Ice_Communicator
, destroy
, NULL
, ZEND_ACC_PUBLIC
)
1103 ZEND_ME(Ice_Communicator
, stringToProxy
, NULL
, ZEND_ACC_PUBLIC
)
1104 ZEND_ME(Ice_Communicator
, proxyToString
, NULL
, ZEND_ACC_PUBLIC
)
1105 ZEND_ME(Ice_Communicator
, propertyToProxy
, NULL
, ZEND_ACC_PUBLIC
)
1106 ZEND_ME(Ice_Communicator
, proxyToProperty
, NULL
, ZEND_ACC_PUBLIC
)
1107 ZEND_ME(Ice_Communicator
, stringToIdentity
, NULL
, ZEND_ACC_PUBLIC
)
1108 ZEND_ME(Ice_Communicator
, identityToString
, NULL
, ZEND_ACC_PUBLIC
)
1109 ZEND_ME(Ice_Communicator
, addObjectFactory
, NULL
, ZEND_ACC_PUBLIC
)
1110 ZEND_ME(Ice_Communicator
, findObjectFactory
, NULL
, ZEND_ACC_PUBLIC
)
1111 ZEND_ME(Ice_Communicator
, getImplicitContext
, NULL
, ZEND_ACC_PUBLIC
)
1112 ZEND_ME(Ice_Communicator
, getProperties
, NULL
, ZEND_ACC_PUBLIC
)
1113 ZEND_ME(Ice_Communicator
, getLogger
, NULL
, ZEND_ACC_PUBLIC
)
1114 ZEND_ME(Ice_Communicator
, getDefaultRouter
, NULL
, ZEND_ACC_PUBLIC
)
1115 ZEND_ME(Ice_Communicator
, setDefaultRouter
, NULL
, ZEND_ACC_PUBLIC
)
1116 ZEND_ME(Ice_Communicator
, getDefaultLocator
, NULL
, ZEND_ACC_PUBLIC
)
1117 ZEND_ME(Ice_Communicator
, setDefaultLocator
, NULL
, ZEND_ACC_PUBLIC
)
1118 ZEND_ME(Ice_Communicator
, flushBatchRequests
, NULL
, ZEND_ACC_PUBLIC
)
1123 createProfile(const string
& name
, const string
& config
, const string
& options TSRMLS_DC
)
1125 ProfileMap::iterator p
= _profiles
.find(name
);
1126 if(p
!= _profiles
.end())
1128 php_error_docref(0 TSRMLS_CC
, E_WARNING
, "duplicate Ice profile `%s'", name
.c_str());
1132 Ice::PropertiesPtr properties
= Ice::createProperties();
1138 properties
->load(config
);
1140 catch(const IceUtil::Exception
& ex
)
1144 php_error_docref(0 TSRMLS_CC
, E_WARNING
, "unable to load Ice configuration file %s:\n%s", config
.c_str(),
1145 ostr
.str().c_str());
1150 if(!options
.empty())
1152 vector
<string
> args
;
1155 args
= IceUtilInternal::Options::split(options
);
1157 catch(const IceUtil::Exception
& ex
)
1161 string msg
= ostr
.str();
1162 php_error_docref(0 TSRMLS_CC
, E_WARNING
, "error occurred while parsing the options `%s':\n%s",
1163 options
.c_str(), msg
.c_str());
1167 properties
->parseCommandLineOptions("", args
);
1170 _profiles
[name
] = properties
;
1175 parseProfiles(const string
& file TSRMLS_DC
)
1178 // The Zend engine doesn't export a function for loading an INI file, so we
1179 // have to do it ourselves. The format is:
1182 // ice.config = config-file
1183 // ice.options = args
1185 ifstream
in(file
.c_str());
1188 php_error_docref(0 TSRMLS_CC
, E_WARNING
, "unable to open Ice profiles in %s", file
.c_str());
1192 string name
, config
, options
;
1194 while(in
.getline(line
, 1024))
1196 const string delim
= " \t\r\n";
1199 string::size_type idx
= s
.find(';');
1200 if(idx
!= string::npos
)
1205 idx
= s
.find_last_not_of(delim
);
1206 if(idx
!= string::npos
&& idx
+ 1 < s
.length())
1211 string::size_type beg
= s
.find_first_not_of(delim
);
1212 if(beg
== string::npos
)
1220 string::size_type end
= s
.find_first_of(" \t]", beg
);
1221 if(end
== string::npos
|| s
[s
.length() - 1] != ']')
1223 php_error_docref(0 TSRMLS_CC
, E_WARNING
, "invalid profile section in file %s:\n%s\n", file
.c_str(),
1230 createProfile(name
, config
, options TSRMLS_CC
);
1235 name
= s
.substr(beg
, end
- beg
);
1239 string::size_type end
= s
.find_first_of(delim
+ "=", beg
);
1240 assert(end
!= string::npos
);
1242 string key
= s
.substr(beg
, end
- beg
);
1244 end
= s
.find('=', end
);
1245 if(end
== string::npos
)
1247 php_error_docref(0 TSRMLS_CC
, E_WARNING
, "invalid profile entry in file %s:\n%s\n", file
.c_str(), line
);
1253 beg
= s
.find_first_not_of(delim
, end
);
1254 if(beg
!= string::npos
)
1257 value
= s
.substr(beg
, end
- beg
);
1260 // Check for quotes and remove them if present
1262 string::size_type qpos
= IceUtilInternal::checkQuote(value
);
1263 if(qpos
!= string::npos
)
1265 value
= value
.substr(1, qpos
- 1);
1269 if(key
== "config" || key
== "ice.config")
1273 else if(key
== "options" || key
== "ice.options")
1279 php_error_docref(0 TSRMLS_CC
, E_WARNING
, "unknown profile entry in file %s:\n%s\n", file
.c_str(), line
);
1284 php_error_docref(0 TSRMLS_CC
, E_WARNING
, "no section for profile entry in file %s:\n%s\n", file
.c_str(),
1293 if(!createProfile(name
, config
, options TSRMLS_CC
))
1303 IcePHP::communicatorInit(TSRMLS_D
)
1306 // We register an interface and a class that implements the interface. This allows
1307 // applications to safely include the Slice-generated code for the type.
1311 // Register the Communicator interface.
1313 zend_class_entry ce
;
1314 #ifdef ICEPHP_USE_NAMESPACES
1315 INIT_NS_CLASS_ENTRY(ce
, STRCAST("Ice"), STRCAST("Communicator"), _interfaceMethods
);
1317 INIT_CLASS_ENTRY(ce
, "Ice_Communicator", _interfaceMethods
);
1319 zend_class_entry
* interface
= zend_register_internal_interface(&ce TSRMLS_CC
);
1322 // Register the Communicator class.
1324 INIT_CLASS_ENTRY(ce
, "IcePHP_Communicator", _classMethods
);
1325 ce
.create_object
= handleAlloc
;
1326 communicatorClassEntry
= zend_register_internal_class(&ce TSRMLS_CC
);
1327 memcpy(&_handlers
, zend_get_std_object_handlers(), sizeof(zend_object_handlers
));
1328 _handlers
.clone_obj
= handleClone
;
1329 zend_class_implements(communicatorClassEntry TSRMLS_CC
, 1, interface
);
1332 // Create the profiles from configuration settings.
1334 const char* empty
= "";
1335 const char* config
= INI_STR("ice.config");
1340 const char* options
= INI_STR("ice.options");
1345 if(!createProfile(_defaultProfileName
, config
, options TSRMLS_CC
))
1350 const char* profiles
= INI_STR("ice.profiles");
1355 if(strlen(profiles
) > 0)
1357 if(!parseProfiles(profiles TSRMLS_CC
))
1362 if(INI_BOOL(const_cast<char*>("ice.hide_profiles")))
1364 memset(const_cast<char*>(profiles
), '*', strlen(profiles
));
1366 // For some reason the code below does not work as expected. It causes a call
1367 // to ini_get_all() to segfault.
1370 if(zend_alter_ini_entry("ice.profiles", sizeof("ice.profiles"), "<hidden>", sizeof("<hidden>") - 1,
1371 PHP_INI_ALL, PHP_INI_STAGE_STARTUP) == FAILURE)
1383 IcePHP::communicatorShutdown(TSRMLS_D
)
1387 IceUtilInternal::MutexPtrLock
<IceUtil::Mutex
> lock(_registeredCommunicatorsMutex
);
1396 // Clearing the map releases the last remaining reference counts of the ActiveCommunicator
1397 // objects. The ActiveCommunicator destructor destroys its communicator.
1399 _registeredCommunicators
.clear();
1405 IcePHP::communicatorRequestInit(TSRMLS_D
)
1407 ICE_G(communicatorMap
) = 0;
1413 IcePHP::communicatorRequestShutdown(TSRMLS_D
)
1415 if(ICE_G(communicatorMap
))
1417 CommunicatorMap
* m
= static_cast<CommunicatorMap
*>(ICE_G(communicatorMap
));
1418 for(CommunicatorMap::iterator p
= m
->begin(); p
!= m
->end(); ++p
)
1420 CommunicatorInfoIPtr info
= p
->second
;
1423 // We need to destroy any object factories installed during this request.
1425 info
->destroyObjectFactories(TSRMLS_C
);
1429 // Deleting the map decrements the reference count of its ActiveCommunicator
1430 // values. If there are no other references to an ActiveCommunicator, its
1431 // destructor destroys the communicator.
1439 IcePHP::ActiveCommunicator::ActiveCommunicator(const Ice::CommunicatorPtr
& c
) :
1440 communicator(c
), expires(0)
1444 IcePHP::ActiveCommunicator::~ActiveCommunicator()
1447 // There are no more references to this communicator, so we can safely destroy it now.
1451 communicator
->destroy();
1458 IcePHP::CommunicatorInfoI::CommunicatorInfoI(const ActiveCommunicatorPtr
& c
, zval
* z
) :
1460 zv(*z
) // This is legal - it simply copies the object's handle.
1465 IcePHP::CommunicatorInfoI::getZval(zval
* z TSRMLS_DC
)
1467 Z_TYPE_P(z
) = IS_OBJECT
;
1468 z
->value
.obj
= zv
.value
.obj
;
1473 IcePHP::CommunicatorInfoI::addRef(TSRMLS_D
)
1475 zval
* p
= const_cast<zval
*>(&zv
);
1476 Z_OBJ_HT_P(p
)->add_ref(p TSRMLS_CC
);
1480 IcePHP::CommunicatorInfoI::decRef(TSRMLS_D
)
1482 zval
* p
= const_cast<zval
*>(&zv
);
1483 Z_OBJ_HT(zv
)->del_ref(p TSRMLS_CC
);
1486 Ice::CommunicatorPtr
1487 IcePHP::CommunicatorInfoI::getCommunicator() const
1489 return ac
->communicator
;
1493 IcePHP::CommunicatorInfoI::addObjectFactory(const string
& id
, zval
* factory TSRMLS_DC
)
1495 ObjectFactoryMap::iterator p
= objectFactories
.find(id
);
1496 if(p
!= objectFactories
.end())
1498 Ice::AlreadyRegisteredException
ex(__FILE__
, __LINE__
);
1499 ex
.kindOfObject
= "object factory";
1501 throwException(ex TSRMLS_CC
);
1505 objectFactories
.insert(ObjectFactoryMap::value_type(id
, factory
));
1506 Z_ADDREF_P(factory
);
1512 IcePHP::CommunicatorInfoI::findObjectFactory(const string
& id
, zval
* zv TSRMLS_DC
)
1514 ObjectFactoryMap::iterator p
= objectFactories
.find(id
);
1515 if(p
!= objectFactories
.end())
1517 *zv
= *p
->second
; // This is legal - it simply copies the object's handle.
1527 IcePHP::CommunicatorInfoI::destroyObjectFactories(TSRMLS_D
)
1529 for(ObjectFactoryMap::iterator p
= objectFactories
.begin(); p
!= objectFactories
.end(); ++p
)
1532 // Invoke the destroy method on each registered PHP factory.
1534 invokeMethod(p
->second
, "destroy" TSRMLS_CC
);
1535 zend_clear_exception(TSRMLS_C
);
1536 zval_ptr_dtor(&p
->second
);
1540 IcePHP::ObjectFactoryI::ObjectFactoryI(const Ice::CommunicatorPtr
& communicator
) :
1541 _communicator(communicator
)
1546 IcePHP::ObjectFactoryI::create(const string
& id
)
1549 // Get the TSRM id for the current request.
1553 CommunicatorMap
* m
= static_cast<CommunicatorMap
*>(ICE_G(communicatorMap
));
1555 CommunicatorMap::iterator p
= m
->find(_communicator
);
1556 assert(p
!= m
->end());
1558 CommunicatorInfoIPtr info
= p
->second
;
1563 // Check if the application has registered a factory for this id.
1565 ObjectFactoryMap::iterator q
= info
->objectFactories
.find(id
);
1566 if(q
== info
->objectFactories
.end())
1568 q
= info
->objectFactories
.find(""); // Look for a default factory.
1570 if(q
!= info
->objectFactories
.end())
1572 factory
= q
->second
;
1576 // Get the type information.
1578 ClassInfoPtr cls
= getClassInfoById(id TSRMLS_CC
);
1588 ZVAL_STRINGL(arg
, STRCAST(id
.c_str()), id
.length(), 1);
1594 const char* func
= "create";
1595 zend_call_method(&factory
, 0, 0, const_cast<char*>(func
), strlen(func
), &obj
, 1, arg
, 0 TSRMLS_CC
);
1603 zval_ptr_dtor(&arg
);
1606 // Bail out if an exception has already been thrown.
1608 if(!obj
|| EG(exception
))
1610 throw AbortMarshaling();
1613 AutoDestroy
destroy(obj
);
1615 if(Z_TYPE_P(obj
) == IS_NULL
)
1620 return new ObjectReader(obj
, cls
, info TSRMLS_CC
);
1624 // If the requested type is an abstract class, then we give up.
1632 // Instantiate the object.
1636 AutoDestroy
destroy(obj
);
1638 if(object_init_ex(obj
, cls
->zce
) != SUCCESS
)
1640 throw AbortMarshaling();
1643 if(!invokeMethod(obj
, ZEND_CONSTRUCTOR_FUNC_NAME TSRMLS_CC
))
1645 throw AbortMarshaling();
1648 return new ObjectReader(obj
, cls
, info TSRMLS_CC
);
1652 IcePHP::ObjectFactoryI::destroy()
1658 IcePHP::ReaperTask::runTimerTask()
1660 IceUtilInternal::MutexPtrLock
<IceUtil::Mutex
> lock(_registeredCommunicatorsMutex
);
1662 IceUtil::Time now
= IceUtil::Time::now();
1663 RegisteredCommunicatorMap::iterator p
= _registeredCommunicators
.begin();
1664 while(p
!= _registeredCommunicators
.end())
1666 if(p
->second
->lastAccess
+ IceUtil::Time::seconds(p
->second
->expires
* 60) <= now
)
1670 p
->second
->communicator
->destroy();
1675 _registeredCommunicators
.erase(p
++);