// Portions Copyright 1995 by Sun Microsystems Inc. // Portions Copyright 1997-2002 by Washington University // All Rights Reserved // // Some CORBA::Object and other operations are specific to this STUB // based implementation, and can neither be used by other kinds of // objref nor have a default implementation. #include "tao/Stub.h" #include "tao/Profile.h" #include "tao/ORB_Core.h" #include "tao/Client_Strategy_Factory.h" #include "tao/Remote_Object_Proxy_Broker.h" #include "tao/Transport_Queueing_Strategies.h" #include "tao/debug.h" #include "tao/Policy_Manager.h" #include "tao/Policy_Set.h" #include "tao/SystemException.h" #include "tao/CDR.h" #if !defined (__ACE_INLINE__) # include "tao/Stub.inl" #endif /* ! __ACE_INLINE__ */ #include "ace/Auto_Ptr.h" #include "ace/CORBA_macros.h" TAO_BEGIN_VERSIONED_NAMESPACE_DECL TAO_Stub::TAO_Stub (const char *repository_id, const TAO_MProfile &profiles, TAO_ORB_Core *orb_core) : type_id (repository_id) , orb_core_ (orb_core) , orb_ () , is_collocated_ (false) , servant_orb_ () , collocated_servant_ (nullptr) , object_proxy_broker_ (the_tao_remote_object_proxy_broker ()) , base_profiles_ ((CORBA::ULong) 0) , forward_profiles_ (nullptr) , forward_profiles_perm_ (nullptr) , profile_in_use_ (nullptr) , profile_success_ (false) , refcount_ (1) #if (TAO_HAS_CORBA_MESSAGING == 1) , policies_ (nullptr) #endif , ior_info_ (nullptr) , forwarded_ior_info_ (nullptr) , collocation_opt_ (orb_core->optimize_collocation_objects ()) , forwarded_on_exception_ (false) { if (this->orb_core_.get() == nullptr) { if (TAO_debug_level > 0) { TAOLIB_DEBUG ((LM_DEBUG, ACE_TEXT ("TAO: (%P|%t) TAO_Stub created with default ") ACE_TEXT ("ORB core\n"))); } this->orb_core_.reset (TAO_ORB_Core_instance ()); } // Duplicate the ORB_Core, otherwise the allocators and other // resources that this class references (directly or indirectly) // could be destroyed before it is time. (void) this->orb_core_->_incr_refcnt (); // Cache the ORB pointer to respond faster to certain queries. this->orb_ = CORBA::ORB::_duplicate (this->orb_core_->orb ()); // Explicit trigger the loading of the client strategy factory at this moment. // Not doing it here could lead to a problem loading it later on during // an upcall (void) this->orb_core_->client_factory (); this->base_profiles (profiles); } TAO_Stub::~TAO_Stub () { ACE_ASSERT (this->refcount_ == 0); if (this->forward_profiles_) reset_profiles (); // reset_profiles doesn't delete forward_profiles_perm_. delete this->forward_profiles_perm_; if (this->profile_in_use_ != nullptr) { // decrease reference count on profile this->profile_in_use_->_decr_refcnt (); this->profile_in_use_ = nullptr; } #if (TAO_HAS_CORBA_MESSAGING == 1) delete this->policies_; #endif delete this->ior_info_; delete this->forwarded_ior_info_; } void TAO_Stub::add_forward_profiles (const TAO_MProfile &mprofiles, const CORBA::Boolean permanent_forward) { // we assume that the profile_in_use_ is being // forwarded! Grab the lock so things don't change. ACE_MT (ACE_GUARD (TAO_SYNCH_MUTEX, guard, this->profile_lock_)); if (TAO_debug_level > 5) { TAOLIB_DEBUG ((LM_DEBUG, ACE_TEXT ("TAO (%P|%t) - Stub::add_forward_profiles, ") ACE_TEXT ("acquired profile lock this = 0x%x\n"), this)); } if (permanent_forward) { // paranoid, reset the bookmark, then clear the forward-stack this->forward_profiles_perm_ = nullptr; this->reset_forward (); } TAO_MProfile *now_pfiles = this->forward_profiles_; if (now_pfiles == nullptr) now_pfiles = &this->base_profiles_; ACE_NEW (this->forward_profiles_, TAO_MProfile (mprofiles)); if (permanent_forward) { // bookmark the new element at bottom of stack this->forward_profiles_perm_ = this->forward_profiles_; } // forwarded profile points to the new IOR (profiles) this->profile_in_use_->forward_to (this->forward_profiles_); // new profile list points back to the list which was forwarded. this->forward_profiles_->forward_from (now_pfiles); // make sure we start at the beginning of mprofiles this->forward_profiles_->rewind (); // Since we have been forwarded, we must set profile_success_ to false // since we are starting a new with a new set of profiles! this->profile_success_ = false; } int TAO_Stub::create_ior_info (IOP::IOR *&ior_info, CORBA::ULong &index) { // We are creating the IOR info. Let us not be disturbed. So grab a // lock. ACE_MT (ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, guard, this->profile_lock_, -1)); if (TAO_debug_level > 5) { TAOLIB_DEBUG ((LM_DEBUG, ACE_TEXT ("TAO (%P|%t) - Stub::create_ior_info, acquired ") ACE_TEXT ("profile lock this = 0x%x\n"), this)); } IOP::IOR *tmp_info = nullptr; if (this->forward_profiles_ != nullptr) { if (this->forwarded_ior_info_ == nullptr) { this->get_profile_ior_info (*this->forward_profiles_, tmp_info); this->forwarded_ior_info_ = tmp_info; } // First we look at the forward profiles to see whether the // profile_in_use is any of it. for (CORBA::ULong i = 0; i < this->forward_profiles_->profile_count (); ++i) { if (this->forward_profiles_->get_profile (i) == this->profile_in_use_) { ior_info = this->forwarded_ior_info_; index = i; return 0; } } } // Else we look at the base profiles if (this->ior_info_ == nullptr) { this->get_profile_ior_info (this->base_profiles_, tmp_info); this->ior_info_ = tmp_info; } for (CORBA::ULong ind = 0; ind < this->base_profiles_.profile_count (); ++ind) { if (this->base_profiles_.get_profile (ind) == this->profile_in_use_) { index = ind; ior_info = this->ior_info_; return 0; } } // Error, there was no match return -1; } const TAO::ObjectKey & TAO_Stub::object_key () const { // Return the profile in use's object key if you see one. if (this->profile_in_use_) return this->profile_in_use_->object_key (); if (this->forward_profiles_) { // Double-checked // FUZZ: disable check_for_ACE_Guard ACE_Guard obj ( const_cast (this->profile_lock_)); // FUZZ: enable check_for_ACE_Guard if (obj.locked () != 0 && this->forward_profiles_ != nullptr) return this->forward_profiles_->get_profile (0)->object_key (); } // If no forwarded profiles, just use the base profile return this->base_profiles_.get_profile (0)->object_key (); } int TAO_Stub::get_profile_ior_info (TAO_MProfile &profiles, IOP::IOR *&ior_info) { ACE_NEW_THROW_EX (ior_info, IOP::IOR (), CORBA::NO_MEMORY ()); // Get the number of elements CORBA::ULong const count = profiles.profile_count (); // Set the number of elements in the sequence of tagged_profile ior_info->profiles.length (count); // Call the create_tagged_profile one every member of the // profile and make the sequence for (CORBA::ULong index = 0; index < count; ++index) { TAO_Profile *prof = profiles.get_profile (index); IOP::TaggedProfile *tp = prof->create_tagged_profile (); if (tp == nullptr) throw ::CORBA::NO_MEMORY (); ior_info->profiles[index] = *tp; } return 0; } void TAO_Stub::is_collocated (CORBA::Boolean collocated) { if (this->is_collocated_ != collocated) { if (collocated && _TAO_Object_Proxy_Broker_Factory_function_pointer != nullptr) { this->object_proxy_broker_ = _TAO_Object_Proxy_Broker_Factory_function_pointer (); } else { this->object_proxy_broker_ = the_tao_remote_object_proxy_broker (); } this->is_collocated_ = collocated; } } // Quick'n'dirty hash of objref data, for partitioning objrefs into // sets. // // NOTE that this must NOT go across the network! CORBA::ULong TAO_Stub::hash (CORBA::ULong max) { // we rely on the profile objects that its address info return this->base_profiles_.hash (max); } // Expensive comparison of objref data, to see if two objrefs // certainly point at the same object. (It's quite OK for this to // return FALSE, and yet have the two objrefs really point to the same // object.) // // NOTE that this must NOT go across the network! // @@ Two object references are the same if any two profiles are the // same! This function is only test the profile in use!!! CORBA::Boolean TAO_Stub::is_equivalent (CORBA::Object_ptr other_obj) { if (CORBA::is_nil (other_obj)) return false; TAO_Profile * const other_profile = other_obj->_stubobj ()->profile_in_use_; TAO_Profile * const this_profile = this->profile_in_use_; if (other_profile == nullptr || this_profile == nullptr) return false; // Compare the profiles return this_profile->is_equivalent (other_profile); } // Memory management TAO_Profile * TAO_Stub::set_profile_in_use_i (TAO_Profile *pfile) { TAO_Profile *const old = this->profile_in_use_; // Since we are actively using this profile we dont want // it to disappear, so increase the reference count by one!! if (pfile && (pfile->_incr_refcnt () == 0)) { TAOLIB_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("(%P|%t) unable to increment profile ref!\n")), 0); } this->profile_in_use_ = pfile; if (old) old->_decr_refcnt (); return this->profile_in_use_; } void TAO_Stub::forward_back_one () { TAO_MProfile *from = forward_profiles_->forward_from (); // Only delete the forward location if it is not permanent if (this->forward_profiles_ != this->forward_profiles_perm_) delete this->forward_profiles_; // the current profile in this profile list is no // longer being forwarded, so set the reference to zero. if (from == &this->base_profiles_) { this->base_profiles_.get_current_profile ()->forward_to (nullptr); this->forward_profiles_ = nullptr; } else { from->get_current_profile ()->forward_to (nullptr); this->forward_profiles_ = from; } } // Note that if the repository ID (typeID) is NULL, it will make // narrowing rather expensive, though it does ensure that type-safe // narrowing code gets thoroughly exercised/debugged! Without a // typeID, the _narrow will be required to make an expensive remote // "is_a" call. // THREADING NOTE: Code below this point is of course thread-safe (at // least on supported threaded platforms), so the caller of these // routines need only ensure that the data being passed in is not // being modified by any other thread. // // **************************************************************** #if (TAO_HAS_CORBA_MESSAGING == 1) // Some policies can only be set locally on the client, while others // can only be exported in the IOR by the server, and yet others can // be set by both by client and server. Furthermore, reconciliation // between client-set values and the ones exported in the IOR is // policy-specific. Therefore, with the current state of things, it // isn't possible to write generic code for that will // work for any policy type. Currently, we take specific action for // each of the known client-exposed policies (above), and simply look // up effective override for any other policy type (below). Later, if // there is a need/desire for generic code, it can be done by pushing // the smarts into the policies implementations, and will involve // modifying PolicyC* and friends, e.g., to add methods for policy // specific reconciliation, etc. CORBA::Policy_ptr TAO_Stub::get_policy (CORBA::PolicyType type) { // No need to lock, the stub only changes its policies at // construction time... CORBA::Policy_var result; if (this->policies_ != nullptr) { result = this->policies_->get_policy (type); } if (CORBA::is_nil (result.in ())) { result = this->orb_core_->get_policy_including_current (type); } return result._retn (); } CORBA::Policy_ptr TAO_Stub::get_cached_policy (TAO_Cached_Policy_Type type) { // No need to lock, the stub only changes its policies at // construction time... CORBA::Policy_var result; if (this->policies_ != nullptr) { result = this->policies_->get_cached_policy (type); } if (CORBA::is_nil (result.in ())) { result = this->orb_core_->get_cached_policy_including_current (type); } return result._retn (); } TAO_Stub * TAO_Stub::set_policy_overrides (const CORBA::PolicyList & policies, CORBA::SetOverrideType set_add) { // Notice the use of an explicit constructor.... std::unique_ptr policy_manager (new TAO_Policy_Set (TAO_POLICY_OBJECT_SCOPE)); if (set_add == CORBA::SET_OVERRIDE) { policy_manager->set_policy_overrides (policies, set_add); } else if (this->policies_ == nullptr) { policy_manager->set_policy_overrides (policies, CORBA::SET_OVERRIDE); } else { policy_manager->copy_from (this->policies_); policy_manager->set_policy_overrides (policies, set_add); } TAO_Stub* stub = this->orb_core_->create_stub (this->type_id.in (), this->base_profiles_); stub->policies_ = policy_manager.release (); // Copy the servant ORB if it is present. stub->servant_orb (this->servant_orb_var ().in ()); return stub; } CORBA::PolicyList * TAO_Stub::get_policy_overrides (const CORBA::PolicyTypeSeq &types) { if (this->policies_ == nullptr) { CORBA::PolicyList *policy_list_ptr = nullptr; ACE_NEW_THROW_EX (policy_list_ptr, CORBA::PolicyList (), CORBA::NO_MEMORY ()); return policy_list_ptr; } else { return this->policies_->get_policy_overrides (types); } } #endif CORBA::Boolean TAO_Stub::marshal (TAO_OutputCDR &cdr) { // do as many outside of locked else-branch as posssible // STRING, a type ID hint if ((cdr << this->type_id.in()) == 0) return 0; if ( ! this->forward_profiles_perm_) { const TAO_MProfile& mprofile = this->base_profiles_; CORBA::ULong const profile_count = mprofile.profile_count (); if ((cdr << profile_count) == 0) return 0; // @@ The MProfile should be locked during this iteration, is there // anyway to achieve that? for (CORBA::ULong i = 0; i < profile_count; ++i) { const TAO_Profile* p = mprofile.get_profile (i); if (p->encode (cdr) == 0) return 0; } } else { ACE_MT (ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, guard, this->profile_lock_, 0)); if (TAO_debug_level > 5) { TAOLIB_DEBUG ((LM_DEBUG, ACE_TEXT ("TAO (%P|%t) - Stub::marshal, acquired ") ACE_TEXT ("profile lock this = 0x%x\n"), this)); } ACE_ASSERT(this->forward_profiles_ !=nullptr); // paranoid - in case of FT the basic_profiles_ would do, too, // but might be dated const TAO_MProfile& mprofile = this->forward_profiles_perm_ ? *(this->forward_profiles_perm_) : this->base_profiles_; CORBA::ULong const profile_count = mprofile.profile_count (); if ((cdr << profile_count) == 0) return 0; // @@ The MProfile should be locked during this iteration, is there // anyway to achieve that? for (CORBA::ULong i = 0; i < profile_count; ++i) { const TAO_Profile* p = mprofile.get_profile (i); if (p->encode (cdr) == 0) return 0; } // release ACE_Lock } return cdr.good_bit (); } TAO_END_VERSIONED_NAMESPACE_DECL