1 //
2 // Copyright (c) ZeroC, Inc. All rights reserved.
3 //
4
5 #include <Communicator.h>
6 #include <Logger.h>
7 #include <Properties.h>
8 #include <Proxy.h>
9 #include <Types.h>
10 #include <Util.h>
11 #include <IceUtil/DisableWarnings.h>
12 #include <IceUtil/Options.h>
13 #include <IceUtil/MutexPtrLock.h>
14 #include <IceUtil/StringUtil.h>
15 #include <IceUtil/Timer.h>
16 #include <fstream>
17
18 #ifdef getcwd
19 # undef getcwd
20 #endif
21 #include <IceUtil/FileUtil.h>
22
23 using namespace std;
24 using namespace IcePHP;
25
26 ZEND_EXTERN_MODULE_GLOBALS(ice)
27
28 //
29 // Class entries represent the PHP class implementations we have registered.
30 //
31 namespace IcePHP
32 {
33
34 zend_class_entry* communicatorClassEntry = 0;
35 zend_class_entry* valueFactoryManagerClassEntry = 0;
36
37 //
38 // An active communicator is in use by at least one request and may have
39 // registered so that it remains active after a request completes. The
40 // communicator is destroyed when there are no more references to this
41 // object.
42 //
43 class ActiveCommunicator : public IceUtil::Shared
44 {
45 public:
46
47 ActiveCommunicator(const Ice::CommunicatorPtr& c);
48 ~ActiveCommunicator();
49
50 const Ice::CommunicatorPtr communicator;
51 vector<string> ids;
52 int expires;
53 IceUtil::Time lastAccess;
54 };
55 typedef IceUtil::Handle<ActiveCommunicator> ActiveCommunicatorPtr;
56
57 class FactoryWrapper;
58 typedef IceUtil::Handle<FactoryWrapper> FactoryWrapperPtr;
59
60 class DefaultValueFactory;
61 typedef IceUtil::Handle<DefaultValueFactory> DefaultValueFactoryPtr;
62
63 //
64 // CommunicatorInfoI encapsulates communicator-related information that
65 // is specific to a PHP "request". In other words, multiple PHP requests
66 // might share the same communicator instance but still need separate
67 // workspaces. For example, we don't want the value factories installed
68 // by one request to influence the behavior of another request.
69 //
70 class CommunicatorInfoI : public CommunicatorInfo
71 {
72 public:
73
74 CommunicatorInfoI(const ActiveCommunicatorPtr&, zval*);
75
76 virtual void getZval(zval*);
77 virtual void addRef(void);
78 virtual void decRef(void);
79
80 virtual Ice::CommunicatorPtr getCommunicator() const;
81
82 bool addFactory(zval*, const string&, bool);
83 FactoryWrapperPtr findFactory(const string&) const;
defaultFactory() const84 Ice::ValueFactoryPtr defaultFactory() const { return _defaultFactory; }
85 void destroyFactories(void);
86
87 const ActiveCommunicatorPtr ac;
88 zval zv;
89
90 private:
91
92 typedef map<string, FactoryWrapperPtr> FactoryMap;
93
94 FactoryMap _factories;
95 DefaultValueFactoryPtr _defaultFactory;
96 };
97 typedef IceUtil::Handle<CommunicatorInfoI> CommunicatorInfoIPtr;
98
99 //
100 // Wraps a PHP object/value factory.
101 //
102 class FactoryWrapper : public Ice::ValueFactory
103 {
104 public:
105
106 FactoryWrapper(zval*, bool, const CommunicatorInfoIPtr&);
107
108 virtual Ice::ValuePtr create(const string&);
109
110 void getZval(zval*);
111
112 bool isObjectFactory() const;
113
114 void destroy(void);
115
116 protected:
117
118 zval _factory;
119 bool _isObjectFactory;
120 CommunicatorInfoIPtr _info;
121 };
122
123 //
124 // Implements the default value factory behavior.
125 //
126 class DefaultValueFactory : public Ice::ValueFactory
127 {
128 public:
129
130 DefaultValueFactory(const CommunicatorInfoIPtr&);
131
132 virtual Ice::ValuePtr create(const string&);
133
setDelegate(const FactoryWrapperPtr & d)134 void setDelegate(const FactoryWrapperPtr& d) { _delegate = d; }
getDelegate() const135 FactoryWrapperPtr getDelegate() const { return _delegate; }
136
137 void destroy(void);
138
139 private:
140
141 FactoryWrapperPtr _delegate;
142 CommunicatorInfoIPtr _info;
143 };
144
145 //
146 // Each PHP request has its own set of value factories. More precisely, there is
147 // a value factory map for each communicator that is created by a PHP request.
148 // (see CommunicatorInfoI).
149 //
150 // We define a custom value factory manager implementation that delegates to
151 // to PHP objects supplied by the application.
152 //
153 // An instance of this class is installed as the communicator's value factory
154 // manager, and the class holds a reference to its communicator. When find() is
155 // invoked, the class resolves the appropriate factory as follows:
156 //
157 // * Using its communicator reference as the key, look up the corresponding
158 // CommunicatorInfoI object in the request-specific communicator map.
159 //
160 // * If the type-id is empty, return the default factory. This factory will
161 // either delegate to an application-supplied default factory (if present) or
162 // default-construct an instance of a concrete Slice class type.
163 //
164 // * For non-empty type-ids, return a wrapper around the application-supplied
165 // factory, if any.
166 //
167 class ValueFactoryManager : public Ice::ValueFactoryManager
168 {
169 public:
170
171 virtual void add(const Ice::ValueFactoryPtr&, const string&);
172 virtual Ice::ValueFactoryPtr find(const string&) const ICE_NOEXCEPT;
173
setCommunicator(const Ice::CommunicatorPtr & c)174 void setCommunicator(const Ice::CommunicatorPtr& c) { _communicator = c; }
getCommunicator() const175 Ice::CommunicatorPtr getCommunicator() const { return _communicator; }
176
177 void getZval(zval*);
178
179 void destroy();
180
181 private:
182
183 Ice::CommunicatorPtr _communicator;
184 };
185 typedef IceUtil::Handle<ValueFactoryManager> ValueFactoryManagerPtr;
186
187 class ReaperTask : public IceUtil::TimerTask
188 {
189 public:
190
191 virtual void runTimerTask();
192 };
193
194 }
195
196 namespace
197 {
198 //
199 // Communicator support.
200 //
201 zend_object_handlers _handlers;
202
203 //
204 // ValueFactoryManager support.
205 //
206 zend_object_handlers _vfmHandlers;
207
208 //
209 // The profile map holds Properties objects corresponding to the "default" profile
210 // (defined via the ice.config & ice.options settings in php.ini) as well as named
211 // profiles defined in an external file.
212 //
213 typedef map<string, Ice::PropertiesPtr> ProfileMap;
214 ProfileMap _profiles;
215 const string _defaultProfileName = "";
216
217 //
218 // This map represents communicators that have been registered so that they can be used
219 // by multiple PHP requests.
220 //
221 typedef map<string, ActiveCommunicatorPtr> RegisteredCommunicatorMap;
222 RegisteredCommunicatorMap _registeredCommunicators;
223 IceUtil::Mutex* _registeredCommunicatorsMutex = 0;
224
225 IceUtil::TimerPtr _timer;
226
227 //
228 // This map is stored in the "global" variables for each PHP request and holds
229 // the communicators that have been created (or registered communicators that have
230 // been used) by the request.
231 //
232 typedef map<Ice::CommunicatorPtr, CommunicatorInfoIPtr> CommunicatorMap;
233
234 class Init
235 {
236 public:
237
Init()238 Init()
239 {
240 _registeredCommunicatorsMutex = new IceUtil::Mutex();
241 }
242
~Init()243 ~Init()
244 {
245 delete _registeredCommunicatorsMutex;
246 _registeredCommunicatorsMutex = 0;
247 }
248 };
249
250 Init init;
251 }
252
253 extern "C"
254 {
255 static zend_object* handleAlloc(zend_class_entry*);
256 static void handleFreeStorage(zend_object*);
257 static zend_object* handleClone(zval*);
258
259 static zend_object* handleVfmAlloc(zend_class_entry*);
260 static void handleVfmFreeStorage(zend_object*);
261 static zend_object* handleVfmClone(zval*);
262 }
263
ZEND_METHOD(Ice_Communicator,__construct)264 ZEND_METHOD(Ice_Communicator, __construct)
265 {
266 runtimeError("communicators cannot be instantiated directly");
267 }
268
ZEND_METHOD(Ice_Communicator,shutdown)269 ZEND_METHOD(Ice_Communicator, shutdown)
270 {
271 CommunicatorInfoIPtr _this = Wrapper<CommunicatorInfoIPtr>::value(getThis() TSRMLS_CC);
272 assert(_this);
273
274 try
275 {
276 _this->getCommunicator()->shutdown();
277 }
278 catch(const IceUtil::Exception& ex)
279 {
280 throwException(ex TSRMLS_CC);
281 }
282 }
283
ZEND_METHOD(Ice_Communicator,isShutdown)284 ZEND_METHOD(Ice_Communicator, isShutdown)
285 {
286 CommunicatorInfoIPtr _this = Wrapper<CommunicatorInfoIPtr>::value(getThis() TSRMLS_CC);
287 assert(_this);
288
289 try
290 {
291 RETURN_BOOL(_this->getCommunicator()->isShutdown() ? 1 : 0);
292 }
293 catch(const IceUtil::Exception& ex)
294 {
295 throwException(ex TSRMLS_CC);
296 RETURN_FALSE;
297 }
298 }
299
ZEND_METHOD(Ice_Communicator,waitForShutdown)300 ZEND_METHOD(Ice_Communicator, waitForShutdown)
301 {
302 CommunicatorInfoIPtr _this = Wrapper<CommunicatorInfoIPtr>::value(getThis() TSRMLS_CC);
303 assert(_this);
304
305 try
306 {
307 _this->getCommunicator()->waitForShutdown();
308 }
309 catch(const IceUtil::Exception& ex)
310 {
311 throwException(ex TSRMLS_CC);
312 }
313 }
314
ZEND_METHOD(Ice_Communicator,destroy)315 ZEND_METHOD(Ice_Communicator, destroy)
316 {
317 CommunicatorInfoIPtr _this = Wrapper<CommunicatorInfoIPtr>::value(getThis());
318 assert(_this);
319
320 Ice::CommunicatorPtr c = _this->getCommunicator();
321 assert(c);
322 CommunicatorMap* m = reinterpret_cast<CommunicatorMap*>(ICE_G(communicatorMap));
323 assert(m);
324 if(m->find(c) != m->end())
325 {
326 m->erase(c);
327
328 //
329 // Remove all registrations.
330 //
331 {
332 IceUtilInternal::MutexPtrLock<IceUtil::Mutex> lock(_registeredCommunicatorsMutex);
333 for(vector<string>::iterator p = _this->ac->ids.begin(); p != _this->ac->ids.end(); ++p)
334 {
335 _registeredCommunicators.erase(*p);
336 }
337 _this->ac->ids.clear();
338 }
339
340 //
341 // We need to destroy any object|value factories installed by this request.
342 //
343 _this->destroyFactories();
344
345 ValueFactoryManagerPtr vfm = ValueFactoryManagerPtr::dynamicCast(c->getValueFactoryManager());
346 assert(vfm);
347 vfm->destroy();
348
349 c->destroy();
350 }
351 }
352
ZEND_METHOD(Ice_Communicator,stringToProxy)353 ZEND_METHOD(Ice_Communicator, stringToProxy)
354 {
355 CommunicatorInfoIPtr _this = Wrapper<CommunicatorInfoIPtr>::value(getThis());
356 assert(_this);
357
358 char* str;
359 size_t strLen;
360 if(zend_parse_parameters(ZEND_NUM_ARGS(), const_cast<char*>("s"), &str, &strLen) != SUCCESS)
361 {
362 RETURN_NULL();
363 }
364 string s(str, strLen);
365
366 try
367 {
368 Ice::ObjectPrx prx = _this->getCommunicator()->stringToProxy(s);
369 if(!createProxy(return_value, prx, _this))
370 {
371 RETURN_NULL();
372 }
373 }
374 catch(const IceUtil::Exception& ex)
375 {
376 throwException(ex);
377 RETURN_NULL();
378 }
379 }
380
ZEND_METHOD(Ice_Communicator,proxyToString)381 ZEND_METHOD(Ice_Communicator, proxyToString)
382 {
383 CommunicatorInfoIPtr _this = Wrapper<CommunicatorInfoIPtr>::value(getThis());
384 assert(_this);
385
386 zval* zv;
387 if(zend_parse_parameters(ZEND_NUM_ARGS(), const_cast<char*>("O!"), &zv, proxyClassEntry) != SUCCESS)
388 {
389 RETURN_NULL();
390 }
391
392 try
393 {
394 string str;
395 if(zv)
396 {
397 Ice::ObjectPrx prx;
398 ProxyInfoPtr info;
399 if(!fetchProxy(zv, prx, info))
400 {
401 RETURN_NULL();
402 }
403 assert(prx);
404 str = prx->ice_toString();
405 }
406 RETURN_STRINGL(STRCAST(str.c_str()), static_cast<int>(str.length()));
407 }
408 catch(const IceUtil::Exception& ex)
409 {
410 throwException(ex);
411 RETURN_NULL();
412 }
413 }
414
ZEND_METHOD(Ice_Communicator,propertyToProxy)415 ZEND_METHOD(Ice_Communicator, propertyToProxy)
416 {
417 CommunicatorInfoIPtr _this = Wrapper<CommunicatorInfoIPtr>::value(getThis());
418 assert(_this);
419
420 char* str;
421 size_t strLen;
422 if(zend_parse_parameters(ZEND_NUM_ARGS(), const_cast<char*>("s"), &str, &strLen) != SUCCESS)
423 {
424 RETURN_NULL();
425 }
426 string s(str, strLen);
427
428 try
429 {
430 Ice::ObjectPrx prx = _this->getCommunicator()->propertyToProxy(s);
431 if(!createProxy(return_value, prx, _this))
432 {
433 RETURN_NULL();
434 }
435 }
436 catch(const IceUtil::Exception& ex)
437 {
438 throwException(ex);
439 RETURN_NULL();
440 }
441 }
442
ZEND_METHOD(Ice_Communicator,proxyToProperty)443 ZEND_METHOD(Ice_Communicator, proxyToProperty)
444 {
445 CommunicatorInfoIPtr _this = Wrapper<CommunicatorInfoIPtr>::value(getThis());
446 assert(_this);
447
448 zval* zv;
449 char* str;
450 size_t strLen;
451 if(zend_parse_parameters(ZEND_NUM_ARGS(), const_cast<char*>("O!s"), &zv, proxyClassEntry, &str, &strLen)
452 != SUCCESS)
453 {
454 RETURN_NULL();
455 }
456
457 string prefix(str, strLen);
458
459 try
460 {
461 if(zv)
462 {
463 Ice::ObjectPrx prx;
464 ProxyInfoPtr info;
465 if(!fetchProxy(zv, prx, info))
466 {
467 RETURN_NULL();
468 }
469 assert(prx);
470
471 Ice::PropertyDict val = _this->getCommunicator()->proxyToProperty(prx, prefix);
472 if(!createStringMap(return_value, val))
473 {
474 RETURN_NULL();
475 }
476 }
477 else
478 {
479 array_init(return_value);
480 }
481 }
482 catch(const IceUtil::Exception& ex)
483 {
484 throwException(ex);
485 RETURN_NULL();
486 }
487 }
488
ZEND_METHOD(Ice_Communicator,stringToIdentity)489 ZEND_METHOD(Ice_Communicator, stringToIdentity)
490 {
491 CommunicatorInfoIPtr _this = Wrapper<CommunicatorInfoIPtr>::value(getThis());
492 assert(_this);
493
494 char* str;
495 size_t strLen;
496 if(zend_parse_parameters(ZEND_NUM_ARGS(), const_cast<char*>("s"), &str, &strLen) != SUCCESS)
497 {
498 RETURN_NULL();
499 }
500 string s(str, strLen);
501
502 try
503 {
504 Ice::Identity id = _this->getCommunicator()->stringToIdentity(s);
505 if(!createIdentity(return_value, id))
506 {
507 RETURN_NULL();
508 }
509 }
510 catch(const IceUtil::Exception& ex)
511 {
512 throwException(ex);
513 RETURN_NULL();
514 }
515 }
516
ZEND_METHOD(Ice_Communicator,identityToString)517 ZEND_METHOD(Ice_Communicator, identityToString)
518 {
519 CommunicatorInfoIPtr _this = Wrapper<CommunicatorInfoIPtr>::value(getThis());
520 assert(_this);
521
522 zend_class_entry* identityClass = idToClass("::Ice::Identity");
523 assert(identityClass);
524
525 zval* zv;
526 if(zend_parse_parameters(ZEND_NUM_ARGS(), const_cast<char*>("O"), &zv, identityClass) != SUCCESS)
527 {
528 RETURN_NULL();
529 }
530 Ice::Identity id;
531 if(!extractIdentity(zv, id))
532 {
533 RETURN_NULL();
534 }
535
536 try
537 {
538 string str = _this->getCommunicator()->identityToString(id);
539 RETURN_STRINGL(STRCAST(str.c_str()), static_cast<int>(str.length()));
540 }
541 catch(const IceUtil::Exception& ex)
542 {
543 throwException(ex);
544 RETURN_NULL();
545 }
546 }
547
ZEND_METHOD(Ice_Communicator,addObjectFactory)548 ZEND_METHOD(Ice_Communicator, addObjectFactory)
549 {
550 CommunicatorInfoIPtr _this = Wrapper<CommunicatorInfoIPtr>::value(getThis());
551 assert(_this);
552
553 zend_class_entry* factoryClass = idToClass("Ice::ObjectFactory");
554 assert(factoryClass);
555
556 zval* factory;
557 char* id;
558 size_t idLen;
559 if(zend_parse_parameters(ZEND_NUM_ARGS(), const_cast<char*>("Os!"), &factory, factoryClass, &id,
560 &idLen) != SUCCESS)
561 {
562 RETURN_NULL();
563 }
564
565 string type;
566 if(id)
567 {
568 type = string(id, idLen);
569 }
570
571 if(!_this->addFactory(factory, type, true))
572 {
573 RETURN_NULL();
574 }
575 }
576
ZEND_METHOD(Ice_Communicator,findObjectFactory)577 ZEND_METHOD(Ice_Communicator, findObjectFactory)
578 {
579 CommunicatorInfoIPtr _this = Wrapper<CommunicatorInfoIPtr>::value(getThis());
580 assert(_this);
581
582 char* id;
583 size_t idLen;
584 if(zend_parse_parameters(ZEND_NUM_ARGS(), const_cast<char*>("s!"), &id, &idLen) != SUCCESS)
585 {
586 RETURN_NULL();
587 }
588
589 string type;
590 if(id)
591 {
592 type = string(id, idLen);
593 }
594
595 FactoryWrapperPtr w = _this->findFactory(type);
596 if(w && w->isObjectFactory())
597 {
598 w->getZval(return_value);
599 }
600 else
601 {
602 RETURN_NULL();
603 }
604 }
605
ZEND_METHOD(Ice_Communicator,getValueFactoryManager)606 ZEND_METHOD(Ice_Communicator, getValueFactoryManager)
607 {
608 if(ZEND_NUM_ARGS() > 0)
609 {
610 WRONG_PARAM_COUNT;
611 }
612
613 CommunicatorInfoIPtr _this = Wrapper<CommunicatorInfoIPtr>::value(getThis());
614 assert(_this);
615
616 try
617 {
618 ValueFactoryManagerPtr vfm =
619 ValueFactoryManagerPtr::dynamicCast(_this->getCommunicator()->getValueFactoryManager());
620 assert(vfm);
621 if(object_init_ex(return_value, valueFactoryManagerClassEntry) != SUCCESS)
622 {
623 runtimeError("unable to initialize properties object");
624 RETURN_NULL();
625 }
626
627 Wrapper<ValueFactoryManagerPtr>* obj = Wrapper<ValueFactoryManagerPtr>::extract(return_value);
628 assert(!obj->ptr);
629 obj->ptr = new ValueFactoryManagerPtr(vfm);
630 }
631 catch(const IceUtil::Exception& ex)
632 {
633 throwException(ex);
634 RETURN_NULL();
635 }
636 }
637
ZEND_METHOD(Ice_Communicator,getImplicitContext)638 ZEND_METHOD(Ice_Communicator, getImplicitContext)
639 {
640 runtimeError("not implemented");
641 }
642
ZEND_METHOD(Ice_Communicator,getProperties)643 ZEND_METHOD(Ice_Communicator, getProperties)
644 {
645 if(ZEND_NUM_ARGS() > 0)
646 {
647 WRONG_PARAM_COUNT;
648 }
649
650 CommunicatorInfoIPtr _this = Wrapper<CommunicatorInfoIPtr>::value(getThis());
651 assert(_this);
652
653 try
654 {
655 Ice::PropertiesPtr props = _this->getCommunicator()->getProperties();
656 if(!createProperties(return_value, props))
657 {
658 RETURN_NULL();
659 }
660 }
661 catch(const IceUtil::Exception& ex)
662 {
663 throwException(ex);
664 RETURN_NULL();
665 }
666 }
667
ZEND_METHOD(Ice_Communicator,getLogger)668 ZEND_METHOD(Ice_Communicator, getLogger)
669 {
670 if(ZEND_NUM_ARGS() > 0)
671 {
672 WRONG_PARAM_COUNT;
673 }
674
675 CommunicatorInfoIPtr _this = Wrapper<CommunicatorInfoIPtr>::value(getThis());
676 assert(_this);
677
678 try
679 {
680 Ice::LoggerPtr logger = _this->getCommunicator()->getLogger();
681 if(!createLogger(return_value, logger))
682 {
683 RETURN_NULL();
684 }
685 }
686 catch(const IceUtil::Exception& ex)
687 {
688 throwException(ex);
689 RETURN_NULL();
690 }
691 }
692
ZEND_METHOD(Ice_Communicator,getDefaultRouter)693 ZEND_METHOD(Ice_Communicator, getDefaultRouter)
694 {
695 if(ZEND_NUM_ARGS() > 0)
696 {
697 WRONG_PARAM_COUNT;
698 }
699
700 CommunicatorInfoIPtr _this = Wrapper<CommunicatorInfoIPtr>::value(getThis());
701 assert(_this);
702
703 try
704 {
705 Ice::RouterPrx router = _this->getCommunicator()->getDefaultRouter();
706 if(router)
707 {
708 ProxyInfoPtr info = getProxyInfo("::Ice::Router");
709 if(!info)
710 {
711 runtimeError("no definition for Ice::Router");
712 RETURN_NULL();
713 }
714 if(!createProxy(return_value, router, info, _this))
715 {
716 RETURN_NULL();
717 }
718 }
719 else
720 {
721 RETURN_NULL();
722 }
723 }
724 catch(const IceUtil::Exception& ex)
725 {
726 throwException(ex);
727 RETURN_NULL();
728 }
729 }
730
ZEND_METHOD(Ice_Communicator,setDefaultRouter)731 ZEND_METHOD(Ice_Communicator, setDefaultRouter)
732 {
733 CommunicatorInfoIPtr _this = Wrapper<CommunicatorInfoIPtr>::value(getThis());
734 assert(_this);
735
736 zval* zv;
737 if(zend_parse_parameters(ZEND_NUM_ARGS(), const_cast<char*>("O!"), &zv, proxyClassEntry) !=
738 SUCCESS)
739 {
740 RETURN_NULL();
741 }
742
743 Ice::ObjectPrx proxy;
744 ProxyInfoPtr info;
745 if(zv && !fetchProxy(zv, proxy, info))
746 {
747 RETURN_NULL();
748 }
749
750 try
751 {
752 Ice::RouterPrx router;
753 if(proxy)
754 {
755 if(!info || !info->isA("::Ice::Router"))
756 {
757 invalidArgument("setDefaultRouter requires a proxy narrowed to Ice::Router");
758 RETURN_NULL();
759 }
760 router = Ice::RouterPrx::uncheckedCast(proxy);
761 }
762 _this->getCommunicator()->setDefaultRouter(router);
763 }
764 catch(const IceUtil::Exception& ex)
765 {
766 throwException(ex);
767 RETURN_NULL();
768 }
769 }
770
ZEND_METHOD(Ice_Communicator,getDefaultLocator)771 ZEND_METHOD(Ice_Communicator, getDefaultLocator)
772 {
773 if(ZEND_NUM_ARGS() > 0)
774 {
775 WRONG_PARAM_COUNT;
776 }
777
778 CommunicatorInfoIPtr _this = Wrapper<CommunicatorInfoIPtr>::value(getThis());
779 assert(_this);
780
781 try
782 {
783 Ice::LocatorPrx locator = _this->getCommunicator()->getDefaultLocator();
784 if(locator)
785 {
786 ProxyInfoPtr info = getProxyInfo("::Ice::Locator");
787 if(!info)
788 {
789 runtimeError("no definition for Ice::Locator");
790 RETURN_NULL();
791 }
792 if(!createProxy(return_value, locator, info, _this))
793 {
794 RETURN_NULL();
795 }
796 }
797 else
798 {
799 RETURN_NULL();
800 }
801 }
802 catch(const IceUtil::Exception& ex)
803 {
804 throwException(ex);
805 RETURN_NULL();
806 }
807 }
808
ZEND_METHOD(Ice_Communicator,setDefaultLocator)809 ZEND_METHOD(Ice_Communicator, setDefaultLocator)
810 {
811 CommunicatorInfoIPtr _this = Wrapper<CommunicatorInfoIPtr>::value(getThis());
812 assert(_this);
813
814 zval* zv;
815 if(zend_parse_parameters(ZEND_NUM_ARGS(), const_cast<char*>("O!"), &zv, proxyClassEntry) !=
816 SUCCESS)
817 {
818 RETURN_NULL();
819 }
820
821 Ice::ObjectPrx proxy;
822 ProxyInfoPtr info;
823 if(zv && !fetchProxy(zv, proxy, info))
824 {
825 RETURN_NULL();
826 }
827
828 try
829 {
830 Ice::LocatorPrx locator;
831 if(proxy)
832 {
833 if(!info || !info->isA("::Ice::Locator"))
834 {
835 invalidArgument("setDefaultLocator requires a proxy narrowed to Ice::Locator");
836 RETURN_NULL();
837 }
838 locator = Ice::LocatorPrx::uncheckedCast(proxy);
839 }
840 _this->getCommunicator()->setDefaultLocator(locator);
841 }
842 catch(const IceUtil::Exception& ex)
843 {
844 throwException(ex);
845 RETURN_NULL();
846 }
847 }
848
ZEND_METHOD(Ice_Communicator,flushBatchRequests)849 ZEND_METHOD(Ice_Communicator, flushBatchRequests)
850 {
851 zval* compress;
852 if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, const_cast<char*>("z"), &compress TSRMLS_CC) != SUCCESS)
853 {
854 RETURN_NULL();
855 }
856
857 if(Z_TYPE_P(compress) != IS_LONG)
858 {
859 invalidArgument("value for 'compress' argument must be an enumerator of CompressBatch" TSRMLS_CC);
860 RETURN_NULL();
861 }
862 Ice::CompressBatch cb = static_cast<Ice::CompressBatch>(Z_LVAL_P(compress));
863
864 CommunicatorInfoIPtr _this = Wrapper<CommunicatorInfoIPtr>::value(getThis() TSRMLS_CC);
865 assert(_this);
866
867 try
868 {
869 _this->getCommunicator()->flushBatchRequests(cb);
870 }
871 catch(const IceUtil::Exception& ex)
872 {
873 throwException(ex TSRMLS_CC);
874 RETURN_NULL();
875 }
876 }
877
ZEND_METHOD(Ice_ValueFactoryManager,__construct)878 ZEND_METHOD(Ice_ValueFactoryManager, __construct)
879 {
880 runtimeError("value factory managers cannot be instantiated directly");
881 }
882
ZEND_METHOD(Ice_ValueFactoryManager,add)883 ZEND_METHOD(Ice_ValueFactoryManager, add)
884 {
885 ValueFactoryManagerPtr _this = Wrapper<ValueFactoryManagerPtr>::value(getThis());
886 assert(_this);
887
888 zend_class_entry* factoryClass = idToClass("Ice::ValueFactory");
889 assert(factoryClass);
890
891 zval* factory;
892 char* id;
893 size_t idLen;
894 if(zend_parse_parameters(ZEND_NUM_ARGS(), const_cast<char*>("Os!"), &factory, factoryClass, &id,
895 &idLen) != SUCCESS)
896 {
897 RETURN_NULL();
898 }
899
900 string type;
901 if(id)
902 {
903 type = string(id, idLen);
904 }
905
906 CommunicatorMap* m = static_cast<CommunicatorMap*>(ICE_G(communicatorMap));
907 assert(m);
908 CommunicatorMap::iterator p = m->find(_this->getCommunicator());
909 assert(p != m->end());
910
911 CommunicatorInfoIPtr info = p->second;
912
913 if(!info->addFactory(factory, type, false))
914 {
915 RETURN_NULL();
916 }
917 }
918
ZEND_METHOD(Ice_ValueFactoryManager,find)919 ZEND_METHOD(Ice_ValueFactoryManager, find)
920 {
921 ValueFactoryManagerPtr _this = Wrapper<ValueFactoryManagerPtr>::value(getThis());
922 assert(_this);
923
924 char* id;
925 size_t idLen;
926 if(zend_parse_parameters(ZEND_NUM_ARGS(), const_cast<char*>("s!"), &id, &idLen) != SUCCESS)
927 {
928 RETURN_NULL();
929 }
930
931 string type;
932 if(id)
933 {
934 type = string(id, idLen);
935 }
936
937 CommunicatorMap* m = static_cast<CommunicatorMap*>(ICE_G(communicatorMap));
938 assert(m);
939 CommunicatorMap::iterator p = m->find(_this->getCommunicator());
940 assert(p != m->end());
941
942 CommunicatorInfoIPtr info = p->second;
943
944 FactoryWrapperPtr w = info->findFactory(type);
945 if(w)
946 {
947 w->getZval(return_value);
948 }
949 else
950 {
951 RETURN_NULL();
952 }
953 }
954
955 #ifdef _WIN32
956 extern "C"
957 #endif
958 static zend_object*
handleAlloc(zend_class_entry * ce)959 handleAlloc(zend_class_entry* ce)
960 {
961 Wrapper<CommunicatorInfoIPtr>* obj = Wrapper<CommunicatorInfoIPtr>::create(ce);
962 assert(obj);
963
964 obj->zobj.handlers = &_handlers;
965
966 return &obj->zobj;
967 }
968
969 #ifdef _WIN32
970 extern "C"
971 #endif
972 static void
handleFreeStorage(zend_object * object)973 handleFreeStorage(zend_object* object)
974 {
975 Wrapper<CommunicatorInfoIPtr>* obj = Wrapper<CommunicatorInfoIPtr>::fetch(object);
976 assert(obj);
977
978 delete obj->ptr;
979 zend_object_std_dtor(object);
980 }
981
982 #ifdef _WIN32
983 extern "C"
984 #endif
985 static zend_object*
handleClone(zval * zv)986 handleClone(zval* zv)
987 {
988 php_error_docref(0, E_ERROR, "communicators cannot be cloned");
989 return 0;
990 }
991
992 #ifdef _WIN32
993 extern "C"
994 #endif
995 static zend_object*
handleVfmAlloc(zend_class_entry * ce)996 handleVfmAlloc(zend_class_entry* ce)
997 {
998 Wrapper<ValueFactoryManagerPtr>* obj = Wrapper<ValueFactoryManagerPtr>::create(ce);
999 assert(obj);
1000
1001 obj->zobj.handlers = &_vfmHandlers;
1002
1003 return &obj->zobj;
1004 }
1005
1006 #ifdef _WIN32
1007 extern "C"
1008 #endif
1009 static void
handleVfmFreeStorage(zend_object * object)1010 handleVfmFreeStorage(zend_object* object)
1011 {
1012 Wrapper<ValueFactoryManagerPtr>* obj = Wrapper<ValueFactoryManagerPtr>::fetch(object);
1013 assert(obj);
1014
1015 delete obj->ptr;
1016 zend_object_std_dtor(object);
1017 }
1018
1019 #ifdef _WIN32
1020 extern "C"
1021 #endif
1022 static zend_object*
handleVfmClone(zval * zv)1023 handleVfmClone(zval* zv)
1024 {
1025 php_error_docref(0, E_ERROR, "value factory managers cannot be cloned");
1026 return 0;
1027 }
1028
1029 static CommunicatorInfoIPtr
createCommunicator(zval * zv,const ActiveCommunicatorPtr & ac)1030 createCommunicator(zval* zv, const ActiveCommunicatorPtr& ac)
1031 {
1032 try
1033 {
1034 if(object_init_ex(zv, communicatorClassEntry) != SUCCESS)
1035 {
1036 runtimeError("unable to initialize communicator object");
1037 return 0;
1038 }
1039
1040 Wrapper<CommunicatorInfoIPtr>* obj = Wrapper<CommunicatorInfoIPtr>::extract(zv);
1041 assert(!obj->ptr);
1042
1043 CommunicatorInfoIPtr info = new CommunicatorInfoI(ac, zv);
1044 obj->ptr = new CommunicatorInfoIPtr(info);
1045
1046 CommunicatorMap* m;
1047 if(ICE_G(communicatorMap))
1048 {
1049 m = reinterpret_cast<CommunicatorMap*>(ICE_G(communicatorMap));
1050 }
1051 else
1052 {
1053 m = new CommunicatorMap;
1054 ICE_G(communicatorMap) = m;
1055 }
1056 m->insert(CommunicatorMap::value_type(ac->communicator, info));
1057
1058 return info;
1059 }
1060 catch(const IceUtil::Exception& ex)
1061 {
1062 throwException(ex);
1063 return 0;
1064 }
1065 }
1066
1067 static CommunicatorInfoIPtr
initializeCommunicator(zval * zv,Ice::StringSeq & args,bool hasArgs,const Ice::InitializationData & initData)1068 initializeCommunicator(zval* zv, Ice::StringSeq& args, bool hasArgs, const Ice::InitializationData& initData)
1069 {
1070 try
1071 {
1072 Ice::CommunicatorPtr c;
1073 if(hasArgs)
1074 {
1075 c = Ice::initialize(args, initData);
1076 }
1077 else
1078 {
1079 c = Ice::initialize(initData);
1080 }
1081 ActiveCommunicatorPtr ac = new ActiveCommunicator(c);
1082
1083 ValueFactoryManagerPtr vfm = ValueFactoryManagerPtr::dynamicCast(c->getValueFactoryManager());
1084 assert(vfm);
1085 vfm->setCommunicator(c);
1086
1087 CommunicatorInfoIPtr info = createCommunicator(zv, ac);
1088 if(!info)
1089 {
1090 try
1091 {
1092 c->destroy();
1093 }
1094 catch(...)
1095 {
1096 }
1097
1098 vfm->destroy();
1099 }
1100
1101 return info;
1102 }
1103 catch(const IceUtil::Exception& ex)
1104 {
1105 throwException(ex);
1106 return 0;
1107 }
1108 }
1109
ZEND_FUNCTION(Ice_initialize)1110 ZEND_FUNCTION(Ice_initialize)
1111 {
1112 if(ZEND_NUM_ARGS() > 2)
1113 {
1114 runtimeError("too many arguments");
1115 RETURN_NULL();
1116 }
1117
1118 zend_class_entry* initClass = idToClass("::Ice::InitializationData");
1119 assert(initClass);
1120
1121 //
1122 // Retrieve the arguments.
1123 //
1124
1125 zval* args = static_cast<zval*>(emalloc(ZEND_NUM_ARGS() * sizeof(zval)));
1126 AutoEfree autoArgs(args); // Call efree on return
1127 if(zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args) == FAILURE)
1128 {
1129 runtimeError("unable to get arguments");
1130 RETURN_NULL();
1131 }
1132
1133 Ice::StringSeq seq;
1134 Ice::InitializationData initData;
1135 zval* zvargs = 0;
1136 zval* zvinit = 0;
1137
1138 //
1139 // The argument options are:
1140 //
1141 // initialize()
1142 // initialize(args)
1143 // initialize(initData)
1144 // initialize(args, initData)
1145 // initialize(initData, args)
1146 //
1147
1148 if(ZEND_NUM_ARGS() > 2)
1149 {
1150 runtimeError("too many arguments to initialize");
1151 RETURN_NULL();
1152 }
1153
1154 if(ZEND_NUM_ARGS() > 0)
1155 {
1156 zval* arg = &args[0];
1157 while(Z_TYPE_P(arg) == IS_REFERENCE)
1158 {
1159 arg = Z_REFVAL_P(arg);
1160 }
1161
1162 if(Z_TYPE_P(arg) == IS_ARRAY)
1163 {
1164 zvargs = arg;
1165 }
1166 else if(Z_TYPE_P(arg) == IS_OBJECT && Z_OBJCE_P(arg) == initClass)
1167 {
1168 zvinit = arg;
1169 }
1170 else
1171 {
1172 invalidArgument("initialize expects an argument list, an InitializationData object, or both");
1173 RETURN_NULL();
1174 }
1175 }
1176
1177 if(ZEND_NUM_ARGS() > 1)
1178 {
1179 zval* arg = &args[1];
1180 while(Z_TYPE_P(arg) == IS_REFERENCE)
1181 {
1182 arg = Z_REFVAL_P(arg);
1183 }
1184
1185 if(Z_TYPE_P(arg) == IS_ARRAY)
1186 {
1187 if(zvargs)
1188 {
1189 invalidArgument("unexpected array argument to initialize");
1190 RETURN_NULL();
1191 }
1192 zvargs = arg;
1193 }
1194 else if(Z_TYPE_P(arg) == IS_OBJECT && Z_OBJCE_P(arg) == initClass)
1195 {
1196 if(zvinit)
1197 {
1198 invalidArgument("unexpected InitializationData argument to initialize");
1199 RETURN_NULL();
1200 }
1201 zvinit = arg;
1202 }
1203 else
1204 {
1205 invalidArgument("initialize expects an argument list, an InitializationData object, or both");
1206 RETURN_NULL();
1207 }
1208 }
1209
1210 if(zvargs && !extractStringArray(zvargs, seq))
1211 {
1212 RETURN_NULL();
1213 }
1214
1215 if(zvinit)
1216 {
1217 zval* data;
1218 string member;
1219
1220 member = "properties";
1221 {
1222 if((data = zend_hash_str_find(Z_OBJPROP_P(zvinit), STRCAST(member.c_str()), member.size())) != 0)
1223 {
1224 assert(Z_TYPE_P(data) == IS_INDIRECT);
1225 if(!fetchProperties(Z_INDIRECT_P(data), initData.properties))
1226 {
1227 RETURN_NULL();
1228 }
1229 }
1230 }
1231
1232 member = "logger";
1233 {
1234 if((data = zend_hash_str_find(Z_OBJPROP_P(zvinit), STRCAST(member.c_str()), member.size())) != 0)
1235 {
1236 assert(Z_TYPE_P(data) == IS_INDIRECT);
1237 if(!fetchLogger(Z_INDIRECT_P(data), initData.logger))
1238 {
1239 RETURN_NULL();
1240 }
1241 }
1242 }
1243 }
1244
1245 initData.compactIdResolver = new IdResolver();
1246 initData.valueFactoryManager = new ValueFactoryManager;
1247
1248 CommunicatorInfoIPtr info = initializeCommunicator(return_value, seq, zvargs != 0, initData);
1249 if(!info)
1250 {
1251 RETURN_NULL();
1252 }
1253
1254 //
1255 // Replace the existing argument array with the filtered set.
1256 //
1257 if(zvargs)
1258 {
1259 zval_dtor(zvargs);
1260 if(!createStringArray(zvargs, seq))
1261 {
1262 RETURN_NULL();
1263 }
1264 }
1265 }
1266
ZEND_FUNCTION(Ice_register)1267 ZEND_FUNCTION(Ice_register)
1268 {
1269 zval* comm;
1270 char* s;
1271 size_t sLen;
1272 zend_long expires = 0;
1273 if(zend_parse_parameters(ZEND_NUM_ARGS(), const_cast<char*>("Os|l"), &comm, communicatorClassEntry, &s,
1274 &sLen, &expires) != SUCCESS)
1275 {
1276 RETURN_NULL();
1277 }
1278
1279 string id(s, sLen);
1280 if(id.empty())
1281 {
1282 invalidArgument("communicator id cannot be empty");
1283 RETURN_NULL();
1284 }
1285
1286 CommunicatorInfoIPtr info = Wrapper<CommunicatorInfoIPtr>::value(comm);
1287 assert(info);
1288
1289 IceUtilInternal::MutexPtrLock<IceUtil::Mutex> lock(_registeredCommunicatorsMutex);
1290
1291 RegisteredCommunicatorMap::iterator p = _registeredCommunicators.find(id);
1292 if(p != _registeredCommunicators.end())
1293 {
1294 if(p->second->communicator != info->getCommunicator())
1295 {
1296 //
1297 // A different communicator is already registered with that ID.
1298 //
1299 RETURN_FALSE;
1300 }
1301 }
1302 else
1303 {
1304 info->ac->ids.push_back(id);
1305 _registeredCommunicators[id] = info->ac;
1306 }
1307
1308 if(expires > 0)
1309 {
1310 //
1311 // Update the expiration time. If a communicator is registered with multiple IDs, we
1312 // always use the most recent expiration setting.
1313 //
1314 info->ac->expires = static_cast<int>(expires);
1315 info->ac->lastAccess = IceUtil::Time::now();
1316
1317 //
1318 // Start the timer if necessary. Reap expired communicators every five minutes.
1319 //
1320 if(!_timer)
1321 {
1322 _timer = new IceUtil::Timer;
1323 _timer->scheduleRepeated(new ReaperTask, IceUtil::Time::seconds(5 * 60));
1324 }
1325 }
1326
1327 RETURN_TRUE;
1328 }
1329
ZEND_FUNCTION(Ice_unregister)1330 ZEND_FUNCTION(Ice_unregister)
1331 {
1332 char* s;
1333 size_t sLen;
1334 if(zend_parse_parameters(ZEND_NUM_ARGS(), const_cast<char*>("s"), &s, &sLen) != SUCCESS)
1335 {
1336 RETURN_NULL();
1337 }
1338
1339 string id(s, sLen);
1340
1341 IceUtilInternal::MutexPtrLock<IceUtil::Mutex> lock(_registeredCommunicatorsMutex);
1342
1343 RegisteredCommunicatorMap::iterator p = _registeredCommunicators.find(id);
1344 if(p == _registeredCommunicators.end())
1345 {
1346 //
1347 // No communicator registered with that ID.
1348 //
1349 RETURN_FALSE;
1350 }
1351
1352 //
1353 // Remove the ID from the ActiveCommunicator's list of registered IDs.
1354 //
1355 ActiveCommunicatorPtr ac = p->second;
1356 vector<string>::iterator q = find(ac->ids.begin(), ac->ids.end(), id);
1357 assert(q != ac->ids.end());
1358 ac->ids.erase(q);
1359
1360 _registeredCommunicators.erase(p);
1361
1362 RETURN_TRUE;
1363 }
1364
ZEND_FUNCTION(Ice_find)1365 ZEND_FUNCTION(Ice_find)
1366 {
1367 char* s;
1368 size_t sLen;
1369 if(zend_parse_parameters(ZEND_NUM_ARGS(), const_cast<char*>("s"), &s, &sLen) != SUCCESS)
1370 {
1371 RETURN_NULL();
1372 }
1373
1374 string id(s, sLen);
1375
1376 IceUtilInternal::MutexPtrLock<IceUtil::Mutex> lock(_registeredCommunicatorsMutex);
1377
1378 RegisteredCommunicatorMap::iterator p = _registeredCommunicators.find(id);
1379 if(p == _registeredCommunicators.end())
1380 {
1381 //
1382 // No communicator registered with that ID.
1383 //
1384 RETURN_NULL();
1385 }
1386
1387 if(p->second->expires > 0)
1388 {
1389 p->second->lastAccess = IceUtil::Time::now();
1390 }
1391
1392 //
1393 // Check if this communicator has already been obtained by the current request.
1394 // If so, we can return the existing PHP object that corresponds to the communicator.
1395 //
1396 CommunicatorMap* m = reinterpret_cast<CommunicatorMap*>(ICE_G(communicatorMap));
1397 if(m)
1398 {
1399 CommunicatorMap::iterator q = m->find(p->second->communicator);
1400 if(q != m->end())
1401 {
1402 q->second->getZval(return_value);
1403 return;
1404 }
1405 }
1406
1407 if(!createCommunicator(return_value, p->second))
1408 {
1409 RETURN_NULL();
1410 }
1411 }
1412
ZEND_FUNCTION(Ice_getProperties)1413 ZEND_FUNCTION(Ice_getProperties)
1414 {
1415 char* s = 0;
1416 size_t sLen;
1417 if(zend_parse_parameters(ZEND_NUM_ARGS(), const_cast<char*>("|s"), &s, &sLen) != SUCCESS)
1418 {
1419 RETURN_NULL();
1420 }
1421
1422 string name;
1423 if(s)
1424 {
1425 name = string(s, sLen);
1426 }
1427
1428 ProfileMap::iterator p = _profiles.find(name);
1429 if(p == _profiles.end())
1430 {
1431 RETURN_NULL();
1432 }
1433
1434 Ice::PropertiesPtr clone = p->second->clone();
1435 if(!createProperties(return_value, clone))
1436 {
1437 RETURN_NULL();
1438 }
1439 }
1440
ZEND_FUNCTION(Ice_identityToString)1441 ZEND_FUNCTION(Ice_identityToString)
1442 {
1443 zend_class_entry* identityClass = idToClass("::Ice::Identity");
1444 assert(identityClass);
1445
1446 zval* zv;
1447 zend_long mode = 0;
1448
1449 if(zend_parse_parameters(ZEND_NUM_ARGS(), const_cast<char*>("O|l"), &zv, identityClass, &mode) != SUCCESS)
1450 {
1451 RETURN_NULL();
1452 }
1453 Ice::Identity id;
1454 if(!extractIdentity(zv, id))
1455 {
1456 RETURN_NULL();
1457 }
1458
1459 try
1460 {
1461 string str = Ice::identityToString(id, static_cast<Ice::ToStringMode>(mode));
1462 RETURN_STRINGL(STRCAST(str.c_str()), static_cast<int>(str.length()));
1463 }
1464 catch(const IceUtil::Exception& ex)
1465 {
1466 throwException(ex);
1467 RETURN_NULL();
1468 }
1469 }
1470
ZEND_FUNCTION(Ice_stringToIdentity)1471 ZEND_FUNCTION(Ice_stringToIdentity)
1472 {
1473 char* str;
1474 size_t strLen;
1475 if(zend_parse_parameters(ZEND_NUM_ARGS(), const_cast<char*>("s"), &str, &strLen) != SUCCESS)
1476 {
1477 RETURN_NULL();
1478 }
1479 string s(str, strLen);
1480
1481 try
1482 {
1483 Ice::Identity id = Ice::stringToIdentity(s);
1484 if(!createIdentity(return_value, id))
1485 {
1486 RETURN_NULL();
1487 }
1488 }
1489 catch(const IceUtil::Exception& ex)
1490 {
1491 throwException(ex);
1492 RETURN_NULL();
1493 }
1494 }
1495
1496 //
1497 // Necessary to suppress warnings from zend_function_entry in php-5.2
1498 // and INI_STR macro.
1499 //
1500 #ifdef __GNUC__
1501 # pragma GCC diagnostic ignored "-Wwrite-strings"
1502 #endif
1503
1504 //
1505 // Predefined methods for Communicator.
1506 //
1507 static zend_function_entry _interfaceMethods[] =
1508 {
1509 {0, 0, 0}
1510 };
1511 static zend_function_entry _classMethods[] =
1512 {
1513 ZEND_ME(Ice_Communicator, __construct, ICE_NULLPTR, ZEND_ACC_PRIVATE|ZEND_ACC_CTOR)
1514 ZEND_ME(Ice_Communicator, shutdown, ICE_NULLPTR, ZEND_ACC_PUBLIC)
1515 ZEND_ME(Ice_Communicator, isShutdown, ICE_NULLPTR, ZEND_ACC_PUBLIC)
1516 ZEND_ME(Ice_Communicator, waitForShutdown, ICE_NULLPTR, ZEND_ACC_PUBLIC)
1517 ZEND_ME(Ice_Communicator, destroy, ICE_NULLPTR, ZEND_ACC_PUBLIC)
1518 ZEND_ME(Ice_Communicator, stringToProxy, ICE_NULLPTR, ZEND_ACC_PUBLIC)
1519 ZEND_ME(Ice_Communicator, proxyToString, ICE_NULLPTR, ZEND_ACC_PUBLIC)
1520 ZEND_ME(Ice_Communicator, propertyToProxy, ICE_NULLPTR, ZEND_ACC_PUBLIC)
1521 ZEND_ME(Ice_Communicator, proxyToProperty, ICE_NULLPTR, ZEND_ACC_PUBLIC)
1522 ZEND_ME(Ice_Communicator, stringToIdentity, ICE_NULLPTR, ZEND_ACC_PUBLIC)
1523 ZEND_ME(Ice_Communicator, identityToString, ICE_NULLPTR, ZEND_ACC_PUBLIC)
1524 ZEND_ME(Ice_Communicator, addObjectFactory, ICE_NULLPTR, ZEND_ACC_PUBLIC)
1525 ZEND_ME(Ice_Communicator, findObjectFactory, ICE_NULLPTR, ZEND_ACC_PUBLIC)
1526 ZEND_ME(Ice_Communicator, getValueFactoryManager, ICE_NULLPTR, ZEND_ACC_PUBLIC)
1527 ZEND_ME(Ice_Communicator, getImplicitContext, ICE_NULLPTR, ZEND_ACC_PUBLIC)
1528 ZEND_ME(Ice_Communicator, getProperties, ICE_NULLPTR, ZEND_ACC_PUBLIC)
1529 ZEND_ME(Ice_Communicator, getLogger, ICE_NULLPTR, ZEND_ACC_PUBLIC)
1530 ZEND_ME(Ice_Communicator, getDefaultRouter, ICE_NULLPTR, ZEND_ACC_PUBLIC)
1531 ZEND_ME(Ice_Communicator, setDefaultRouter, ICE_NULLPTR, ZEND_ACC_PUBLIC)
1532 ZEND_ME(Ice_Communicator, getDefaultLocator, ICE_NULLPTR, ZEND_ACC_PUBLIC)
1533 ZEND_ME(Ice_Communicator, setDefaultLocator, ICE_NULLPTR, ZEND_ACC_PUBLIC)
1534 ZEND_ME(Ice_Communicator, flushBatchRequests, ICE_NULLPTR, ZEND_ACC_PUBLIC)
1535 {0, 0, 0}
1536 };
1537
1538 //
1539 // Predefined methods for ValueFactoryManager.
1540 //
1541 static zend_function_entry _vfmInterfaceMethods[] =
1542 {
1543 {0, 0, 0}
1544 };
1545 static zend_function_entry _vfmClassMethods[] =
1546 {
1547 ZEND_ME(Ice_ValueFactoryManager, __construct, ICE_NULLPTR, ZEND_ACC_PRIVATE|ZEND_ACC_CTOR)
1548 ZEND_ME(Ice_ValueFactoryManager, add, ICE_NULLPTR, ZEND_ACC_PUBLIC)
1549 ZEND_ME(Ice_ValueFactoryManager, find, ICE_NULLPTR, ZEND_ACC_PUBLIC)
1550 {0, 0, 0}
1551 };
1552
1553 static bool
createProfile(const string & name,const string & config,const string & options)1554 createProfile(const string& name, const string& config, const string& options)
1555 {
1556 ProfileMap::iterator p = _profiles.find(name);
1557 if(p != _profiles.end())
1558 {
1559 php_error_docref(0, E_WARNING, "duplicate Ice profile `%s'", name.c_str());
1560 return false;
1561 }
1562
1563 Ice::PropertiesPtr properties = Ice::createProperties();
1564
1565 if(!config.empty())
1566 {
1567 try
1568 {
1569 properties->load(config);
1570 }
1571 catch(const IceUtil::Exception& ex)
1572 {
1573 ostringstream ostr;
1574 ex.ice_print(ostr);
1575 php_error_docref(0, E_WARNING, "unable to load Ice configuration file %s:\n%s", config.c_str(),
1576 ostr.str().c_str());
1577 return false;
1578 }
1579 }
1580
1581 if(!options.empty())
1582 {
1583 vector<string> args;
1584 try
1585 {
1586 args = IceUtilInternal::Options::split(options);
1587 }
1588 catch(const IceUtil::Exception& ex)
1589 {
1590 ostringstream ostr;
1591 ex.ice_print(ostr);
1592 string msg = ostr.str();
1593 php_error_docref(0, E_WARNING, "error occurred while parsing the options `%s':\n%s",
1594 options.c_str(), msg.c_str());
1595 return false;
1596 }
1597
1598 properties->parseCommandLineOptions("", args);
1599 }
1600
1601 _profiles[name] = properties;
1602 return true;
1603 }
1604
1605 static bool
parseProfiles(const string & file)1606 parseProfiles(const string& file)
1607 {
1608 //
1609 // The Zend engine doesn't export a function for loading an INI file, so we
1610 // have to do it ourselves. The format is:
1611 //
1612 // [profile-name]
1613 // ice.config = config-file
1614 // ice.options = args
1615 //
1616 ifstream in(IceUtilInternal::streamFilename(file).c_str());
1617 if(!in)
1618 {
1619 php_error_docref(0, E_WARNING, "unable to open Ice profiles in %s", file.c_str());
1620 return false;
1621 }
1622
1623 string name, config, options;
1624 char line[1024];
1625 while(in.getline(line, 1024))
1626 {
1627 const string delim = " \t\r\n";
1628 string s = line;
1629
1630 string::size_type idx = s.find(';');
1631 if(idx != string::npos)
1632 {
1633 s.erase(idx);
1634 }
1635
1636 idx = s.find_last_not_of(delim);
1637 if(idx != string::npos && idx + 1 < s.length())
1638 {
1639 s.erase(idx + 1);
1640 }
1641
1642 string::size_type beg = s.find_first_not_of(delim);
1643 if(beg == string::npos)
1644 {
1645 continue;
1646 }
1647
1648 if(s[beg] == '[')
1649 {
1650 beg++;
1651 string::size_type end = s.find_first_of(" \t]", beg);
1652 if(end == string::npos || s[s.length() - 1] != ']')
1653 {
1654 php_error_docref(0, E_WARNING, "invalid profile section in file %s:\n%s\n", file.c_str(),
1655 line);
1656 return false;
1657 }
1658
1659 if(!name.empty())
1660 {
1661 createProfile(name, config, options);
1662 config.clear();
1663 options.clear();
1664 }
1665
1666 name = s.substr(beg, end - beg);
1667 }
1668 else
1669 {
1670 string::size_type end = s.find_first_of(delim + "=", beg);
1671 assert(end != string::npos);
1672
1673 string key = s.substr(beg, end - beg);
1674
1675 end = s.find('=', end);
1676 if(end == string::npos)
1677 {
1678 php_error_docref(0, E_WARNING, "invalid profile entry in file %s:\n%s\n", file.c_str(), line);
1679 return false;
1680 }
1681 ++end;
1682
1683 string value;
1684 beg = s.find_first_not_of(delim, end);
1685 if(beg != string::npos)
1686 {
1687 end = s.length();
1688 value = s.substr(beg, end - beg);
1689
1690 //
1691 // Check for quotes and remove them if present
1692 //
1693 string::size_type qpos = IceUtilInternal::checkQuote(value);
1694 if(qpos != string::npos)
1695 {
1696 value = value.substr(1, qpos - 1);
1697 }
1698 }
1699
1700 if(key == "config" || key == "ice.config")
1701 {
1702 config = value;
1703 }
1704 else if(key == "options" || key == "ice.options")
1705 {
1706 options = value;
1707 }
1708 else
1709 {
1710 php_error_docref(0, E_WARNING, "unknown profile entry in file %s:\n%s\n", file.c_str(), line);
1711 }
1712
1713 if(name.empty())
1714 {
1715 php_error_docref(0, E_WARNING, "no section for profile entry in file %s:\n%s\n", file.c_str(),
1716 line);
1717 return false;
1718 }
1719 }
1720 }
1721
1722 if(!name.empty())
1723 {
1724 if(!createProfile(name, config, options))
1725 {
1726 return false;
1727 }
1728 }
1729
1730 return true;
1731 }
1732
1733 bool
communicatorInit(void)1734 IcePHP::communicatorInit(void)
1735 {
1736 //
1737 // We register an interface and a class that implements the interface. This allows
1738 // applications to safely include the Slice-generated code for the type.
1739 //
1740
1741 //
1742 // Register the Communicator interface.
1743 //
1744 zend_class_entry ce;
1745 #ifdef ICEPHP_USE_NAMESPACES
1746 INIT_NS_CLASS_ENTRY(ce, "Ice", "Communicator", _interfaceMethods);
1747 #else
1748 INIT_CLASS_ENTRY(ce, "Ice_Communicator", _interfaceMethods);
1749 #endif
1750 zend_class_entry* interface = zend_register_internal_interface(&ce);
1751
1752 //
1753 // Register the Communicator class.
1754 //
1755 INIT_CLASS_ENTRY(ce, "IcePHP_Communicator", _classMethods);
1756 ce.create_object = handleAlloc;
1757 communicatorClassEntry = zend_register_internal_class(&ce);
1758 memcpy(&_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
1759 _handlers.clone_obj = handleClone;
1760 _handlers.free_obj = handleFreeStorage;
1761 _handlers.offset = XtOffsetOf(Wrapper<CommunicatorInfoIPtr>, zobj);
1762 zend_class_implements(communicatorClassEntry, 1, interface);
1763
1764 //
1765 // Register the ValueFactoryManager interface.
1766 //
1767 #ifdef ICEPHP_USE_NAMESPACES
1768 INIT_NS_CLASS_ENTRY(ce, "Ice", "ValueFactoryManager", _vfmInterfaceMethods);
1769 #else
1770 INIT_CLASS_ENTRY(ce, "Ice_ValueFactoryManager", _vfmInterfaceMethods);
1771 #endif
1772 zend_class_entry* vfmInterface = zend_register_internal_interface(&ce);
1773
1774 //
1775 // Register the ValueFactoryManager class.
1776 //
1777 INIT_CLASS_ENTRY(ce, "IcePHP_ValueFactoryManager", _vfmClassMethods);
1778 ce.create_object = handleVfmAlloc;
1779 valueFactoryManagerClassEntry = zend_register_internal_class(&ce);
1780 memcpy(&_vfmHandlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
1781 _vfmHandlers.clone_obj = handleVfmClone;
1782 _vfmHandlers.free_obj = handleVfmFreeStorage;
1783 _vfmHandlers.offset = XtOffsetOf(Wrapper<ValueFactoryManagerPtr>, zobj);
1784 zend_class_implements(valueFactoryManagerClassEntry, 1, vfmInterface);
1785
1786 //
1787 // Create the profiles from configuration settings.
1788 //
1789 const char* empty = "";
1790 const char* config = INI_STR("ice.config"); // Needs to be a string literal!
1791 if(!config)
1792 {
1793 config = empty;
1794 }
1795 const char* options = INI_STR("ice.options"); // Needs to be a string literal!
1796 if(!options)
1797 {
1798 options = empty;
1799 }
1800 if(!createProfile(_defaultProfileName, config, options))
1801 {
1802 return false;
1803 }
1804
1805 const char* profiles = INI_STR("ice.profiles"); // Needs to be a string literal!
1806 if(!profiles)
1807 {
1808 profiles = empty;
1809 }
1810 if(strlen(profiles) > 0)
1811 {
1812 if(!parseProfiles(profiles))
1813 {
1814 return false;
1815 }
1816
1817 if(INI_BOOL(const_cast<char*>("ice.hide_profiles")))
1818 {
1819 memset(const_cast<char*>(profiles), '*', strlen(profiles));
1820 //
1821 // For some reason the code below does not work as expected. It causes a call
1822 // to ini_get_all() to segfault.
1823 //
1824 /*
1825 if(zend_alter_ini_entry("ice.profiles", sizeof("ice.profiles"), "<hidden>", sizeof("<hidden>") - 1,
1826 PHP_INI_ALL, PHP_INI_STAGE_STARTUP) == FAILURE)
1827 {
1828 return false;
1829 }
1830 */
1831 }
1832 }
1833
1834 return true;
1835 }
1836
1837 bool
communicatorShutdown(void)1838 IcePHP::communicatorShutdown(void)
1839 {
1840 _profiles.clear();
1841
1842 IceUtilInternal::MutexPtrLock<IceUtil::Mutex> lock(_registeredCommunicatorsMutex);
1843
1844 if(_timer)
1845 {
1846 _timer->destroy();
1847 _timer = 0;
1848 }
1849
1850 //
1851 // Clearing the map releases the last remaining reference counts of the ActiveCommunicator
1852 // objects. The ActiveCommunicator destructor destroys its communicator.
1853 //
1854 _registeredCommunicators.clear();
1855
1856 return true;
1857 }
1858
1859 bool
communicatorRequestInit(void)1860 IcePHP::communicatorRequestInit(void)
1861 {
1862 ICE_G(communicatorMap) = 0;
1863
1864 return true;
1865 }
1866
1867 bool
communicatorRequestShutdown(void)1868 IcePHP::communicatorRequestShutdown(void)
1869 {
1870 if(ICE_G(communicatorMap))
1871 {
1872 CommunicatorMap* m = static_cast<CommunicatorMap*>(ICE_G(communicatorMap));
1873 for(CommunicatorMap::iterator p = m->begin(); p != m->end(); ++p)
1874 {
1875 CommunicatorInfoIPtr info = p->second;
1876
1877 //
1878 // We need to destroy any object|value factories installed during this request.
1879 //
1880 info->destroyFactories();
1881 }
1882
1883 //
1884 // Deleting the map decrements the reference count of its ActiveCommunicator
1885 // values. If there are no other references to an ActiveCommunicator, its
1886 // destructor destroys the communicator.
1887 //
1888 delete m;
1889 }
1890
1891 return true;
1892 }
1893
ActiveCommunicator(const Ice::CommunicatorPtr & c)1894 IcePHP::ActiveCommunicator::ActiveCommunicator(const Ice::CommunicatorPtr& c) :
1895 communicator(c), expires(0)
1896 {
1897 }
1898
~ActiveCommunicator()1899 IcePHP::ActiveCommunicator::~ActiveCommunicator()
1900 {
1901 //
1902 // There are no more references to this communicator, so we can safely destroy it now.
1903 //
1904 try
1905 {
1906 communicator->destroy();
1907 }
1908 catch(...)
1909 {
1910 }
1911 }
1912
FactoryWrapper(zval * factory,bool isObjectFactory,const CommunicatorInfoIPtr & info)1913 IcePHP::FactoryWrapper::FactoryWrapper(zval* factory, bool isObjectFactory, const CommunicatorInfoIPtr& info) :
1914 _isObjectFactory(isObjectFactory),
1915 _info(info)
1916 {
1917 ZVAL_COPY(&_factory, factory);
1918 }
1919
1920 Ice::ValuePtr
create(const string & id)1921 IcePHP::FactoryWrapper::create(const string& id)
1922 {
1923 //
1924 // Get the TSRM id for the current request.
1925 //
1926
1927 //
1928 // Get the type information.
1929 //
1930 ClassInfoPtr cls;
1931 if(id == Ice::Object::ice_staticId())
1932 {
1933 //
1934 // When the ID is that of Ice::Object, it indicates that the stream has not
1935 // found a factory and is providing us an opportunity to preserve the object.
1936 //
1937 cls = getClassInfoById("::Ice::UnknownSlicedValue");
1938 }
1939 else
1940 {
1941 cls = getClassInfoById(id);
1942 }
1943
1944 if(!cls)
1945 {
1946 return 0;
1947 }
1948
1949 zval arg;
1950 ZVAL_STRINGL(&arg, STRCAST(id.c_str()), static_cast<int>(id.length()));
1951
1952 zval obj;
1953 ZVAL_UNDEF(&obj);
1954
1955 zend_try
1956 {
1957 assert(Z_TYPE(_factory) == IS_OBJECT);
1958 zend_call_method(&_factory, 0, 0, const_cast<char*>("create"), sizeof("create") - 1, &obj, 1, &arg, 0);
1959 }
1960 zend_catch
1961 {
1962 // obj;
1963 }
1964 zend_end_try();
1965
1966 //
1967 // Bail out if an exception has already been thrown.
1968 //
1969 if(Z_ISUNDEF(obj) || EG(exception))
1970 {
1971 throw AbortMarshaling();
1972 }
1973
1974 AutoDestroy destroy(&obj);
1975
1976 if(Z_TYPE(obj) == IS_NULL)
1977 {
1978 return 0;
1979 }
1980
1981 return new ObjectReader(&obj, cls, _info);
1982 }
1983
1984 void
getZval(zval * factory)1985 IcePHP::FactoryWrapper::getZval(zval* factory)
1986 {
1987 ZVAL_DUP(factory, &_factory);
1988 }
1989
1990 bool
isObjectFactory() const1991 IcePHP::FactoryWrapper::isObjectFactory() const
1992 {
1993 return _isObjectFactory;
1994 }
1995
1996 void
destroy(void)1997 IcePHP::FactoryWrapper::destroy(void)
1998 {
1999 if(_isObjectFactory)
2000 {
2001 //
2002 // Invoke the destroy method on the PHP factory.
2003 //
2004 invokeMethod(&_factory, "destroy");
2005 zend_clear_exception();
2006 }
2007 zval_ptr_dtor(&_factory);
2008 _info = 0;
2009 }
2010
DefaultValueFactory(const CommunicatorInfoIPtr & info)2011 IcePHP::DefaultValueFactory::DefaultValueFactory(const CommunicatorInfoIPtr& info) :
2012 _info(info)
2013 {
2014 }
2015
2016 Ice::ValuePtr
create(const string & id)2017 IcePHP::DefaultValueFactory::create(const string& id)
2018 {
2019 //
2020 // Get the TSRM id for the current request.
2021 //
2022 if(_delegate)
2023 {
2024 Ice::ValuePtr v = _delegate->create(id);
2025 if(v)
2026 {
2027 return v;
2028 }
2029 }
2030
2031 //
2032 // Get the type information.
2033 //
2034 ClassInfoPtr cls;
2035 if(id == Ice::Object::ice_staticId())
2036 {
2037 //
2038 // When the ID is that of Ice::Object, it indicates that the stream has not
2039 // found a factory and is providing us an opportunity to preserve the object.
2040 //
2041 cls = getClassInfoById("::Ice::UnknownSlicedValue");
2042 }
2043 else
2044 {
2045 cls = getClassInfoById(id);
2046 }
2047
2048 if(!cls)
2049 {
2050 return 0;
2051 }
2052
2053 //
2054 // Instantiate the object.
2055 //
2056 zval obj;
2057
2058 if(object_init_ex(&obj, const_cast<zend_class_entry*>(cls->zce)) != SUCCESS)
2059 {
2060 throw AbortMarshaling();
2061 }
2062
2063 if(!invokeMethod(&obj, ZEND_CONSTRUCTOR_FUNC_NAME))
2064 {
2065 throw AbortMarshaling();
2066 }
2067
2068 return new ObjectReader(&obj, cls, _info);
2069 }
2070
2071 void
destroy(void)2072 IcePHP::DefaultValueFactory::destroy(void)
2073 {
2074 if(_delegate)
2075 {
2076 _delegate->destroy();
2077 _delegate = 0;
2078 }
2079 _info = 0;
2080 }
2081
CommunicatorInfoI(const ActiveCommunicatorPtr & c,zval * z)2082 IcePHP::CommunicatorInfoI::CommunicatorInfoI(const ActiveCommunicatorPtr& c, zval* z) :
2083 ac(c),
2084 _defaultFactory(new DefaultValueFactory(this))
2085 {
2086 ZVAL_COPY_VALUE(&zv, z);
2087 }
2088
2089 void
getZval(zval * z)2090 IcePHP::CommunicatorInfoI::getZval(zval* z)
2091 {
2092 ZVAL_COPY_VALUE(z, &zv);
2093 addRef();
2094 }
2095
2096 void
addRef(void)2097 IcePHP::CommunicatorInfoI::addRef(void)
2098 {
2099 Z_ADDREF_P(&zv);
2100 }
2101
2102 void
decRef(void)2103 IcePHP::CommunicatorInfoI::decRef(void)
2104 {
2105 Z_DELREF_P(&zv);
2106 }
2107
2108 Ice::CommunicatorPtr
getCommunicator() const2109 IcePHP::CommunicatorInfoI::getCommunicator() const
2110 {
2111 return ac->communicator;
2112 }
2113
2114 bool
addFactory(zval * factory,const string & id,bool isObjectFactory)2115 IcePHP::CommunicatorInfoI::addFactory(zval* factory, const string& id, bool isObjectFactory)
2116 {
2117 if(id.empty())
2118 {
2119 if(_defaultFactory->getDelegate())
2120 {
2121 Ice::AlreadyRegisteredException ex(__FILE__, __LINE__);
2122 ex.kindOfObject = "value factory";
2123 ex.id = id;
2124 throwException(ex);
2125 return false;
2126 }
2127
2128 _defaultFactory->setDelegate(new FactoryWrapper(factory, isObjectFactory, this));
2129 }
2130 else
2131 {
2132 FactoryMap::iterator p = _factories.find(id);
2133 if(p != _factories.end())
2134 {
2135 Ice::AlreadyRegisteredException ex(__FILE__, __LINE__);
2136 ex.kindOfObject = "value factory";
2137 ex.id = id;
2138 throwException(ex);
2139 return false;
2140 }
2141 _factories.insert(FactoryMap::value_type(id, new FactoryWrapper(factory, isObjectFactory, this)));
2142 }
2143
2144 return true;
2145 }
2146
2147 FactoryWrapperPtr
findFactory(const string & id) const2148 IcePHP::CommunicatorInfoI::findFactory(const string& id) const
2149 {
2150 if(id.empty())
2151 {
2152 return _defaultFactory->getDelegate();
2153 }
2154 else
2155 {
2156 FactoryMap::const_iterator p = _factories.find(id);
2157 if(p != _factories.end())
2158 {
2159 assert(p->second);
2160 return p->second;
2161 }
2162 }
2163 return 0;
2164 }
2165
2166 void
destroyFactories(void)2167 IcePHP::CommunicatorInfoI::destroyFactories(void)
2168 {
2169 for(FactoryMap::iterator p = _factories.begin(); p != _factories.end(); ++p)
2170 {
2171 p->second->destroy();
2172 }
2173 _factories.clear();
2174 _defaultFactory->destroy();
2175 }
2176
2177 void
add(const Ice::ValueFactoryPtr &,const string &)2178 IcePHP::ValueFactoryManager::add(const Ice::ValueFactoryPtr&, const string&)
2179 {
2180 //
2181 // We don't support factories registered in C++.
2182 //
2183 throw Ice::FeatureNotSupportedException(__FILE__, __LINE__, "C++ value factory");
2184 }
2185
2186 Ice::ValueFactoryPtr
find(const string & id) const2187 IcePHP::ValueFactoryManager::find(const string& id) const ICE_NOEXCEPT
2188 {
2189 //
2190 // Get the TSRM id for the current request.
2191 //
2192
2193 CommunicatorMap* m = static_cast<CommunicatorMap*>(ICE_G(communicatorMap));
2194 assert(m);
2195 CommunicatorMap::iterator p = m->find(_communicator);
2196 assert(p != m->end());
2197
2198 CommunicatorInfoIPtr info = p->second;
2199
2200 if(id.empty())
2201 {
2202 return info->defaultFactory();
2203 }
2204 else
2205 {
2206 return info->findFactory(id);
2207 }
2208 }
2209
2210 void
destroy()2211 IcePHP::ValueFactoryManager::destroy()
2212 {
2213 _communicator = 0;
2214 }
2215
2216 void
runTimerTask()2217 IcePHP::ReaperTask::runTimerTask()
2218 {
2219 IceUtilInternal::MutexPtrLock<IceUtil::Mutex> lock(_registeredCommunicatorsMutex);
2220
2221 IceUtil::Time now = IceUtil::Time::now();
2222 RegisteredCommunicatorMap::iterator p = _registeredCommunicators.begin();
2223 while(p != _registeredCommunicators.end())
2224 {
2225 if(p->second->lastAccess + IceUtil::Time::seconds(p->second->expires * 60) <= now)
2226 {
2227 try
2228 {
2229 p->second->communicator->destroy();
2230 }
2231 catch(...)
2232 {
2233 }
2234 _registeredCommunicators.erase(p++);
2235 }
2236 else
2237 {
2238 ++p;
2239 }
2240 }
2241 }
2242