1 // -*- Mode: C++; -*-
2 //                            Package   : omniORB
3 // callDescriptor.h           Created on: 12/1998
4 //                            Author    : David Riddoch (djr)
5 //                            Author    : Duncan Grisby (dgrisby)
6 //
7 //    Copyright (C) 2003-2012 Apasphere Ltd
8 //    Copyright (C) 1996-1999 AT&T Research Cambridge
9 //
10 //    This file is part of the omniORB library.
11 //
12 //    The omniORB library is free software; you can redistribute it and/or
13 //    modify it under the terms of the GNU Lesser General Public
14 //    License as published by the Free Software Foundation; either
15 //    version 2.1 of the License, or (at your option) any later version.
16 //
17 //    This library is distributed in the hope that it will be useful,
18 //    but WITHOUT ANY WARRANTY; without even the implied warranty of
19 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20 //    Lesser General Public License for more details.
21 //
22 //    You should have received a copy of the GNU Lesser General Public
23 //    License along with this library. If not, see http://www.gnu.org/licenses/
24 //
25 //
26 //    Object that encapsulates a call to be performed
27 //
28 
29 #ifndef __OMNIORB_CALLDESCRIPTOR_H__
30 #define __OMNIORB_CALLDESCRIPTOR_H__
31 
32 #ifdef _core_attr
33 # error "A local CPP macro _core_attr has already been defined."
34 #endif
35 
36 #if defined(_OMNIORB_LIBRARY)
37 #     define _core_attr
38 #else
39 #     define _core_attr _OMNIORB_NTDLL_IMPORT
40 #endif
41 
42 
43 class omniObjRef;
44 class omniServant;
45 class omniCurrent;
46 
47 OMNI_NAMESPACE_BEGIN(omni)
48 class omniOrbPOA;
49 class giopAddress;
OMNI_NAMESPACE_END(omni)50 OMNI_NAMESPACE_END(omni)
51 
52 //////////////////////////////////////////////////////////////////////
53 ///////////////////////// omniCallDescriptor /////////////////////////
54 //////////////////////////////////////////////////////////////////////
55 
56 class omniCallDescriptor {
57 public:
58   typedef void (*LocalCallFn)(omniCallDescriptor*, omniServant*);
59 
60   struct InterceptorFn {
61     LocalCallFn    fn;
62     InterceptorFn* next;
63   };
64 
65   // Call descriptor constructor.
66   //
67   // lcfn         -- function used to perform a local call on a servant
68   // op           -- operation name. Null represents a LocateRequest
69   //                 rather than a normal call
70   // op_len       -- length of operation name
71   // oneway       -- true if a oneway call
72   // user_excns   -- set of valid user exceptions or null if not known
73   // n_user_excns -- number of user exceptions
74   // is_upcall    -- true if this is an upcall to a servant
75 
76   inline omniCallDescriptor(LocalCallFn	      lcfn,
77 			    const char*	      op_,
78 			    size_t	      op_len_,
79 			    _CORBA_Boolean    oneway,
80 			    const char*const* user_excns_,
81 			    int		      n_user_excns_,
82                             _CORBA_Boolean    is_upcall_)
83     : pd_do_call(sd_interceptor_call ? sd_interceptor_call : lcfn),
84       pd_local_call(lcfn),
85       pd_op(op_), pd_oplen(op_len_),
86       pd_user_excns(user_excns_),
87       pd_n_user_excns(n_user_excns_),
88       pd_is_oneway(oneway),
89       pd_is_upcall(is_upcall_),
90       pd_contains_values(0),
91       pd_first_address_used(0),
92       pd_current_address(0),
93       pd_objref(0),
94       pd_poa(0),
95       pd_localId(0)
96   {}
97 
98   virtual ~omniCallDescriptor() {}
99 
100   //////////////////////////////////////////////////
101   // Methods to implement call on the client side //
102   //////////////////////////////////////////////////
103 
104   virtual void initialiseCall(cdrStream&);
105 
106   virtual void marshalArguments(cdrStream&);
107   // Defaults to no arguments.
108 
109   virtual void unmarshalReturnedValues(cdrStream&);
110   // Defaults to no arguments and returns void.
111 
112   virtual void userException(cdrStream& stream, _OMNI_NS(IOP_C)* iop_client,
113 			     const char*);
114   // Called on the client side to handle a user exception.
115   // Defaults to no user exceptions, and thus throws CORBA::UNKNOWN.
116   // Most versions of this throw either a user exception or
117   // CORBA::UNKNOWN, but it is permitted to return successfully. This
118   // is done by DII, for example.
119   // If iop_client is non-zero, must call iop_client->RequestCompleted().
120 
121   void validateUserException(const CORBA::UserException& ex);
122   // Called to validate a user exception in a local call. If the call
123   // descriptor knows the exception is not valid for the call, throws
124   // CORBA::UNKNOWN. If the exception is valid, or the call descriptor
125   // does not know, returns.
126 
127   //////////////////////////////////////////////////
128   // Methods to implement call on the server side //
129   //////////////////////////////////////////////////
130 
131   virtual void unmarshalArguments(cdrStream&);
132   // Defaults to no arguments.
133 
134   virtual void marshalReturnedValues(cdrStream&);
135   // Defaults to no arguments and returns void.
136 
137   ////////////////
138   // Invocation //
139   ////////////////
140 
141   // Called by stub code to perform a local call.
142   inline void doLocalCall(omniServant* servant) {
143     pd_do_call(this, servant);
144   }
145 
146   // Interceptor functions *must* call this to continue the call.
147   inline void interceptedCall(omniServant* servant) {
148     LocalCallFn lcfn;
149     if (pd_interceptor_stack) {
150       lcfn = pd_interceptor_stack->fn;
151       pd_interceptor_stack = pd_interceptor_stack->next;
152     }
153     else
154       lcfn = pd_local_call;
155 
156     lcfn(this, servant);
157   }
158 
159   ///////////////
160   // Accessors //
161   ///////////////
162 
163   inline const char* op() const            { return pd_op;           }
164   inline size_t op_len() const             { return pd_oplen;        }
165   inline _CORBA_Boolean is_oneway() const  { return pd_is_oneway;    }
166   inline void set_oneway(_CORBA_Boolean o) { pd_is_oneway = o;       }
167   inline const char* const* user_excns()   { return pd_user_excns;   }
168   inline int n_user_excns()                { return pd_n_user_excns; }
169   inline _CORBA_Boolean is_upcall() const  { return pd_is_upcall;    }
170 
171   inline _CORBA_Boolean haslocalCallFn() const {
172     return (pd_local_call) ? 1 : 0;
173   }
174 
175   inline const _OMNI_NS(giopAddress)* firstAddressUsed() {
176     return pd_first_address_used;
177   }
178 
179   inline void firstAddressUsed(const _OMNI_NS(giopAddress)* a) {
180     pd_first_address_used = a;
181   }
182 
183   inline const _OMNI_NS(giopAddress)* currentAddress() {
184     return pd_current_address;
185   }
186 
187   inline void currentAddress(const _OMNI_NS(giopAddress)* a) {
188     pd_current_address = a;
189   }
190 
191   inline const omni_time_t& getDeadline() const {
192     return pd_deadline;
193   }
194 
195   inline void setDeadline(const omni_time_t& deadline) {
196     pd_deadline = deadline;
197   }
198 
199   inline void containsValues(_CORBA_Boolean v) {
200     pd_contains_values = v;
201   }
202   inline _CORBA_Boolean containsValues() {
203     return pd_contains_values;
204   }
205   // If pd_contains_values is true, the arguments / return values
206   // contain valuetypes. The spec requires that values are always
207   // passed by value, so local calls must make copies. Since values
208   // can be shared by separate arguments, the whole argument list must
209   // be copied in a single operation. We do this by marshalling via a
210   // temprary memory buffer. This is slow, so it can be turned off by
211   // setting the copyValuesInLocalCalls parameter to false.
212 
213 
214   /////////////////////
215   // Current support //
216   /////////////////////
217 
218   inline void objref(omniObjRef* o)           { pd_objref = o; }
219   inline omniObjRef* objref()                 { return pd_objref; }
220   inline void poa(_OMNI_NS(omniOrbPOA*) poa_) { pd_poa = poa_; }
221   inline _OMNI_NS(omniOrbPOA*) poa()          { return pd_poa; }
222   inline void localId(omniLocalIdentity* lid) { pd_localId = lid; }
223   inline omniLocalIdentity* localId()         { return pd_localId; }
224 
225 
226   //////////////////////////////
227   // Interceptor registration //
228   //////////////////////////////
229 
230   static void addInterceptor(LocalCallFn func);
231   static void removeInterceptor(LocalCallFn func);
232 
233 
234 private:
235   LocalCallFn                  pd_do_call;
236   LocalCallFn                  pd_local_call;
237   const char*                  pd_op;
238   size_t                       pd_oplen;
239   const char*const*            pd_user_excns;
240   int                          pd_n_user_excns;
241   _CORBA_Boolean               pd_is_oneway;
242   _CORBA_Boolean               pd_is_upcall;
243   _CORBA_Boolean               pd_contains_values;
244 
245   const _OMNI_NS(giopAddress)* pd_first_address_used;
246   const _OMNI_NS(giopAddress)* pd_current_address;
247   // state holder for the giop transport in relation to this call. Not
248   // manipulated by this class other than the access functions.
249   // Initialised to 0 in ctor.
250 
251   /////////////////////
252   // Current support //
253   /////////////////////
254 
255   omniCurrent*                 pd_current;
256   omniCallDescriptor*          pd_current_next;
257   // The omniCurrent object maintains a stack of call descriptors,
258   // representing nested colocated calls. These pointers are
259   // maintained by functions in omniCurrent.
260 
261   omniObjRef*                  pd_objref;
262   // This is set on the client side to indicate the object reference
263   // invoked on. It is used for two things: 1. to check if a servant
264   // found by the in process identity can be used in a direct local
265   // call; 2. as the return value from PortableServer::Current::
266   // get_reference(). In the case of a remote upcall, this is zero,
267   // and an objref is constructed from information in the local id on
268   // request.
269 
270   _OMNI_NS(omniOrbPOA*)        pd_poa;
271   omniLocalIdentity*           pd_localId;
272   // Both always set on the way through the POA during an upcall.
273 
274   ////////////////////////////
275   // Deadline for this call //
276   ////////////////////////////
277 
278   // This is a state holder for the call. Not manipulated by this class
279   // other than the access functions. Initialised to 0 in ctor.
280   omni_time_t                  pd_deadline;
281 
282 
283   ///////////////////////
284   // Call interceptors //
285   ///////////////////////
286 
287   static _core_attr LocalCallFn sd_interceptor_call;
288   // Function used in place of the normal local call function if
289   // interceptors are registered. Initialises the interceptor stack
290   // and calls the first interceptor in the stack.
291 
292   static void setupInterception(omniCallDescriptor* cd, omniServant* servant);
293   // Function assigned to sd_interceptor_call when interceptors are registered.
294 
295   static _core_attr InterceptorFn* sd_interceptor_stack;
296   InterceptorFn*                   pd_interceptor_stack;
297   // Global interceptor stack and this call descriptor's pointer into it.
298 
299 
300   /////////////////////
301   // Not implemented //
302   /////////////////////
303 
304   omniCallDescriptor(const omniCallDescriptor&);
305   omniCallDescriptor& operator = (const omniCallDescriptor&);
306   // Not implemented.
307 };
308 
309 
310 //////////////////////////////////////////////////////////////////////
311 ///////////////////////// omniAsyncCallDescriptor ////////////////////
312 //////////////////////////////////////////////////////////////////////
313 
314 class omniAsyncCallDescriptor : public omniCallDescriptor
315 {
316 public:
317   // Constructor for normal synchronous calls. Created on the stack.
omniAsyncCallDescriptor(LocalCallFn lcfn,const char * op_,size_t op_len_,_CORBA_Boolean oneway,const char * const * user_excns_,int n_user_excns_,_CORBA_Boolean is_upcall_)318   inline omniAsyncCallDescriptor(LocalCallFn	   lcfn,
319 				 const char*	   op_,
320 				 size_t		   op_len_,
321 				 _CORBA_Boolean	   oneway,
322 				 const char*const* user_excns_,
323 				 int		   n_user_excns_,
324 				 _CORBA_Boolean	   is_upcall_)
325     : omniCallDescriptor(lcfn, op_, op_len_, oneway,
326 			 user_excns_, n_user_excns_,
327 			 is_upcall_),
328       pd_exception(0),
329       pd_cond(0),
330       pd_set_cond(0)
331   {}
332 
333   // Constructor for asynchronous calls. Created on the heap.
334   //
335   // In callback AMI, completeCallback() makes the callback to the
336   // ReplyHandler, then deletes this; in polling AMI, the poller
337   // valuetype owns the call descriptor and deletes it when the poller
338   // is deleted.
omniAsyncCallDescriptor(LocalCallFn lcfn,const char * op_,size_t op_len_,_CORBA_Boolean oneway,const char * const * user_excns_,int n_user_excns_)339   inline omniAsyncCallDescriptor(LocalCallFn	   lcfn,
340 				 const char*	   op_,
341 				 size_t		   op_len_,
342 				 _CORBA_Boolean	   oneway,
343 				 const char*const* user_excns_,
344 				 int		   n_user_excns_)
345     : omniCallDescriptor(lcfn, op_, op_len_, oneway,
346 			 user_excns_, n_user_excns_, 0),
347       pd_exception(0),
348       pd_cond(0),
349       pd_set_cond(0),
350       pd_complete(0),
351       pd_do_callback(1)
352   {}
353 
354   virtual ~omniAsyncCallDescriptor();
355 
356   virtual void completeCallback();
357 
358   // Handler set / get. Object reference is a Messaging::ReplyHandler
359   // subclass.
360   virtual void 	      setHandler(omniObjRef* objref);
361   virtual omniObjRef* getHandler();
362 
363 
setComplete()364   inline void setComplete()
365   {
366     _CORBA_Boolean do_callback;
367     {
368       omni_tracedmutex_lock l(sd_lock);
369       do_callback = pd_do_callback;
370       pd_complete = 1;
371 
372       if (pd_cond)
373 	pd_cond->broadcast();
374 
375       if (pd_set_cond)
376         pd_set_cond->signal();
377     }
378     if (do_callback)
379       completeCallback();
380   }
381 
isComplete()382   inline _CORBA_Boolean isComplete()
383   {
384     omni_tracedmutex_lock l(sd_lock);
385     return pd_complete;
386   }
387 
lockedIsComplete()388   inline _CORBA_Boolean lockedIsComplete()
389   {
390     ASSERT_OMNI_TRACEDMUTEX_HELD(sd_lock, 1);
391     return pd_complete;
392   }
393 
wait()394   inline void wait()
395   {
396     omni_tracedmutex_lock l(sd_lock);
397 
398     if (pd_complete)
399       return;
400 
401     if (!pd_cond)
402       pd_cond = new omni_tracedcondition(&sd_lock,
403 					 "omniAsyncCallDescriptor::pd_cond");
404 
405     while (!pd_complete)
406       pd_cond->wait();
407   }
408 
wait(const omni_time_t & t)409   inline _CORBA_Boolean wait(const omni_time_t& t)
410   {
411     omni_tracedmutex_lock l(sd_lock);
412 
413     if (pd_complete)
414       return 1;
415 
416     if (!pd_cond)
417       pd_cond = new omni_tracedcondition(&sd_lock,
418 					 "omniAsyncCallDescriptor::pd_cond");
419 
420     pd_cond->timedwait(t);
421     return pd_complete;
422   }
423 
isReady(CORBA::ULong timeout)424   inline _CORBA_Boolean isReady(CORBA::ULong timeout)
425   {
426     if (timeout == 0)
427       return isComplete();
428 
429     if (timeout == 0xffffffff) {
430       wait();
431       return 1;
432     }
433 
434     omni_time_t timeout_tt(timeout / 1000, (timeout % 1000) * 1000000);
435     omni_time_t deadline;
436     omni_thread::get_time(deadline, timeout_tt);
437 
438     return wait(deadline);
439   }
440 
441 
storeException(const CORBA::Exception & ex)442   inline void storeException(const CORBA::Exception& ex)
443   {
444     pd_exception = CORBA::Exception::_duplicate(&ex);
445   }
446 
exceptionOccurred()447   inline _CORBA_Boolean exceptionOccurred()
448   {
449     return pd_exception ? 1 : 0;
450   }
451 
raiseException()452   inline void raiseException()
453   {
454     if (pd_exception)
455       pd_exception->_raise();
456   }
457 
getException()458   inline CORBA::Exception* getException()
459   {
460     CORBA::Exception* ex = pd_exception;
461     pd_exception = 0;
462     return ex;
463   }
464 
addToSet(omni_tracedcondition * set_cond)465   inline _CORBA_Boolean addToSet(omni_tracedcondition* set_cond)
466   {
467     ASSERT_OMNI_TRACEDMUTEX_HELD(sd_lock, 1);
468 
469     if (pd_set_cond)
470       return 0;
471 
472     pd_set_cond = set_cond;
473     return 1;
474   }
475 
remFromSet(omni_tracedcondition * set_cond)476   inline void remFromSet(omni_tracedcondition* set_cond)
477   {
478     ASSERT_OMNI_TRACEDMUTEX_HELD(sd_lock, 1);
479     OMNIORB_ASSERT(pd_set_cond == set_cond);
480 
481     pd_set_cond = 0;
482   }
483 
484   static _core_attr omni_tracedmutex sd_lock;
485 
486 protected:
487   CORBA::Exception*       pd_exception;
488   omni_tracedcondition*   pd_cond;
489   omni_tracedcondition*   pd_set_cond;
490   _CORBA_Boolean          pd_complete;
491   _CORBA_Boolean          pd_do_callback;
492 
493   // Not implemented
494   omniAsyncCallDescriptor(const omniAsyncCallDescriptor&);
495   omniAsyncCallDescriptor& operator=(const omniAsyncCallDescriptor&);
496 };
497 
498 
499 //////////////////////////////////////////////////////////////////////
500 /////////////////////////// omniStdCallDesc //////////////////////////
501 //////////////////////////////////////////////////////////////////////
502 
503 //  This just provides a namespace for pre-defined call descriptors.
504 
505 class omniStdCallDesc {
506 public:
507 
508   // Mangled signature: void
509   typedef omniCallDescriptor void_call;
510 
511   // Mangled signature: _cCORBA_mObject_i_cstring
512   class _cCORBA_mObject_i_cstring : public omniCallDescriptor {
513   public:
514     inline _cCORBA_mObject_i_cstring(LocalCallFn lcfn, const char* op_,
515 		     size_t oplen, const char* a_0,
516 		     _CORBA_Boolean upcall=0) :
517       omniCallDescriptor(lcfn, op_, oplen, 0, 0, 0, upcall),
518       arg_0( OMNI_CONST_CAST(char*, a_0) ) {}
519 
~_cCORBA_mObject_i_cstring()520     inline ~_cCORBA_mObject_i_cstring() {
521       if (is_upcall()) {
522 	_CORBA_String_helper::dealloc(arg_0);
523       }
524     }
525 
526     void marshalArguments(cdrStream&);
527     void unmarshalReturnedValues(cdrStream&);
528     void unmarshalArguments(cdrStream&);
529     void marshalReturnedValues(cdrStream&);
530 
result()531     inline CORBA::Object_ptr result() { return pd_result._retn(); }
532 
533     char* arg_0;
534     CORBA::Object_var pd_result;
535   };
536 
537 };
538 
539 
540 //////////////////////////////////////////////////////////////////////
541 ///////////////////// omniLocalOnlyCallDescriptor ////////////////////
542 //////////////////////////////////////////////////////////////////////
543 
544 // This class is needed to support calls to objects which may only
545 // reside in the local address space.  eg. ServantLocator,
546 // ServantActivator, AdapterActivator.
547 
548 class omniLocalOnlyCallDescriptor : public omniCallDescriptor {
549 public:
550   omniLocalOnlyCallDescriptor(LocalCallFn lcfn, const char* op_,
551 			      size_t op_len_, _CORBA_Boolean is_oneway_ = 0)
552     : omniCallDescriptor(lcfn, op_, op_len_, is_oneway_, 0, 0, 0) {}
553 
554   // Only useful as client side descriptor. No set up for server side upcall.
555 
556   // We only need to override this one -- as it will throw an
557   // exception, so the other members won't get called.
558   void marshalArguments(cdrStream&);
559 };
560 
561 #undef _core_attr
562 
563 #endif  // __OMNIORB_CALLDESCRIPTOR_H__
564