// $Id$ /* -*- C++ -*- */ //============================================================================= /** * @file FT_TestReplica_i.cpp * * $Id$ * * Implements CORBA interface TestReplica. * * @author Dale Wilson */ //============================================================================= // #include "FT_TestReplica_i.h" #include "FT_ReplicaFactory_i.h" #include "tao/ORB_Constants.h" #include "FT_TestReplicaC.h" // FUZZ: disable check_for_streams_include #include "ace/streams.h" #include "ace/OS_NS_stdio.h" ////////////////// // TestReplica_i namespace { /** * Endian neutral store of long into indexable object. * BUFFER can be sequence of Octet, unsigned char[], etc. * * TODO: Find this a good home. * * @param state an object that supports char & operator[] (size_t index); * @param offset is the position within state where the first character should be stored. * @param value is the data to be inserted into state. */ template void storeLong(BUFFER & state, size_t offset, long value) { state[offset ] = static_cast (value >> 24); state[offset + 1] = static_cast (value >> 16); state[offset + 2] = static_cast (value >> 8); state[offset + 3] = static_cast (value ); } /** * Endian neutral load of long from indexable object. * BUFFER can be sequence of Octet, unsigned char[], etc. * * TODO: Find this a good home. * * @param state an object that supports const char & operator[] (size_t index) const; * @param offset is the position within state where the first character can be found * @returns value is the data loaded from state. */ template long loadLong(const BUFFER & state, size_t offset) { long result = ((state[offset ] & 0xFF) << 24) | ((state[offset + 1] & 0xFF) << 16) | ((state[offset + 2] & 0xFF) << 8) | ((state[offset + 3] & 0xFF) ); return result; } } // NO_RESPONSE ->no reinvocation #define FAULT_CODE CORBA::TRANSIENT // Macros to simplify suicide. #define KEVORKIAN(value, method) \ if (this->death_pending_ == (FT_TEST::TestReplica::value)){ \ suicide (#value " in method " #method); \ ACE_THROW (FAULT_CODE ( \ CORBA::SystemException::_tao_minor_code ( \ TAO::VMCID, \ EFAULT), \ CORBA::COMPLETED_NO)); \ } else ; #define KEVORKIAN_DURING(method) \ if (this->death_pending_ == FT_TEST::TestReplica::BEFORE_REPLY ){\ suicide ("read-only method " #method); \ ACE_THROW (FAULT_CODE ( \ CORBA::SystemException::_tao_minor_code ( \ TAO::VMCID, \ EFAULT), \ CORBA::COMPLETED_NO)); \ } else ; #define KEVORKIAN_RETURN(value, method, result) \ if (this->death_pending_ == (FT_TEST::TestReplica::value)){ \ suicide (#value " in method " #method); \ ACE_THROW_RETURN (FAULT_CODE ( \ CORBA::SystemException::_tao_minor_code ( \ TAO::VMCID, \ EFAULT), \ CORBA::COMPLETED_NO), \ result); \ } else ; #define KEVORKIAN_DURING_RETURN(method, result) \ if (this->death_pending_ == FT_TEST::TestReplica::BEFORE_REPLY ){\ suicide ("read-only method " #method); \ ACE_THROW_RETURN (FAULT_CODE ( \ CORBA::SystemException::_tao_minor_code ( \ TAO::VMCID, \ EFAULT), \ CORBA::COMPLETED_NO), \ result); \ } else ; ////////////////////////////////////////////////// // class FT_TestReplica_i construction/destruction FT_TestReplica_i::FT_TestReplica_i (FT_ReplicaFactory_i * factory, const char * name, unsigned long factory_id) : death_pending_ (FT_TEST::TestReplica::NOT_YET) , verbose_ (1) , name_ (name) , factory_id_ (factory_id) , factory_ (factory) , orb_ (0) , poa_ (0) , object_id_ (0) { // cout << name_.c_str() << '@' << this->factory_->location() << '#' << this->factory_id_ << " Construct" << endl; } FT_TestReplica_i::~FT_TestReplica_i () { // cout << name_.c_str() << '@' << this->factory_->location() << '#' << this->factory_id_ << " Destruct" << endl; } void FT_TestReplica_i::suicide(const char * note) { ACE_OS::fprintf (stdout, "%s@%s#%lu Simulate FAULT_CODE fault: %s\n", name_.c_str(), this->factory_->location(), this->factory_id_, note); // Tell the poa we aren't accepting future calls this->poa_->deactivate_object (this->object_id_.in ()); } ///////////////////////////////////////////////////// // class FT_TestReplica_i public, non-CORBA interface //static const char * FT_TestReplica_i::repository_id() { ACE_DECLARE_NEW_CORBA_ENV; const char * id = FT_TEST::_tc_TestReplica->id(ACE_ENV_SINGLE_ARG_PARAMETER); ACE_CHECK_RETURN (0); return id; } int FT_TestReplica_i::parse_args (int argc, char *argv[]) { ACE_UNUSED_ARG (argc); ACE_UNUSED_ARG (argv); return 0; } //static const char * FT_TestReplica_i::usage_options() { return ""; } unsigned long FT_TestReplica_i::factory_id()const { return this->factory_id_; } ::PortableServer::POA_ptr FT_TestReplica_i::_default_POA (ACE_ENV_SINGLE_ARG_DECL_NOT_USED) { return ::PortableServer::POA::_duplicate(this->poa_.in ()); } PortableServer::ObjectId FT_TestReplica_i::object_id()const { return this->object_id_.in(); } /** * Initialize this object. * @param orbManager our ORB -- we keep var to it. * @return zero for success; nonzero is process return code for failure. */ int FT_TestReplica_i::init (CORBA::ORB_var & orb ACE_ENV_ARG_DECL) { this->orb_ = orb; // Use the ROOT POA for now CORBA::Object_var poa_object = this->orb_->resolve_initial_references (TAO_OBJID_ROOTPOA ACE_ENV_ARG_PARAMETER); ACE_CHECK_RETURN (-1); if (CORBA::is_nil (poa_object.in ())) ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT (" (%P|%t) Unable to initialize the POA.\n")), -1); // Get the POA object. this->poa_ = PortableServer::POA::_narrow (poa_object.in () ACE_ENV_ARG_PARAMETER); ACE_CHECK_RETURN (-1); if (CORBA::is_nil(this->poa_.in ())) { ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT (" (%P|%t) Unable to narrow the POA.\n")), -1); } PortableServer::POAManager_var poa_manager = this->poa_->the_POAManager (ACE_ENV_SINGLE_ARG_PARAMETER); ACE_CHECK_RETURN (-1); poa_manager->activate (ACE_ENV_SINGLE_ARG_PARAMETER); ACE_CHECK_RETURN (-1); // Register with the POA. this->object_id_ = this->poa_->activate_object (this ACE_ENV_ARG_PARAMETER); ACE_CHECK_RETURN (-1); return 0; } void FT_TestReplica_i::_remove_ref (ACE_ENV_SINGLE_ARG_DECL) { ////////////////////////////////////////////////// // WARNING: The following call invokes fini then deletes this object this->factory_->remove_replica(this->factory_id_, this ACE_ENV_ARG_PARAMETER); } int FT_TestReplica_i::fini (ACE_ENV_SINGLE_ARG_DECL_NOT_USED) { return 0; } ///////////////////////////////////////////////////// // class FT_TestReplica_i: PullMonitorable interface CORBA::Boolean FT_TestReplica_i::is_alive (ACE_ENV_SINGLE_ARG_DECL) ACE_THROW_SPEC ((CORBA::SystemException)) { KEVORKIAN_RETURN(DURING_IS_ALIVE, is_alive, 0) ACE_ERROR ((LM_ERROR, "%s@%s#%d: is_alive: %d\n", this->name_.c_str(), this->factory_->location(), this->factory_id_, (this->death_pending_ != FT_TEST::TestReplica::DENY_IS_ALIVE) )); return this->death_pending_ != FT_TEST::TestReplica::DENY_IS_ALIVE; } ///////////////////////////////////////////////////// // class FT_TestReplica_i: Updateable interface FT::State * FT_TestReplica_i::get_update (ACE_ENV_SINGLE_ARG_DECL) ACE_THROW_SPEC ((CORBA::SystemException, FT::NoUpdateAvailable)) { KEVORKIAN_RETURN(DURING_GET_UPDATE, get_update, 0) long counter = load(); ::FT::State_var vState = new ::FT::State; vState->length(sizeof(counter)); storeLong(vState, 0, counter); return vState._retn(); } void FT_TestReplica_i::set_update (const FT::State & s ACE_ENV_ARG_DECL) ACE_THROW_SPEC ((CORBA::SystemException, FT::InvalidUpdate)) { #if defined(FT_TEST_LACKS_UPDATE) ACE_THROW ( FT::InvalidUpdate () ); #else // FT_TEST_LACKS_UPDATE KEVORKIAN(BEFORE_SET_UPDATE, set_update) long counter = loadLong(s, 0); store(counter); KEVORKIAN(AFTER_SET_UPDATE, set_update) #endif // FT_TEST_LACKS_UPDATE } ///////////////////////////////////////////////////// // class FT_TestReplica_i: Checkpointable interface ::FT::State * FT_TestReplica_i::get_state (ACE_ENV_SINGLE_ARG_DECL) ACE_THROW_SPEC ((CORBA::SystemException, FT::NoStateAvailable)) { #if defined(FT_TEST_LACKS_STATE) ACE_THROW( FT::NoStateAvailable () ); #else // FT_TEST_LACKS_STATE KEVORKIAN_RETURN(DURING_GET_STATE, get_state, 0) long counter = load(); ::FT::State_var vState = new ::FT::State; vState->length(sizeof(counter)); storeLong(vState, 0, counter); return vState._retn(); #endif // FT_TEST_LACKS_STATE } void FT_TestReplica_i::set_state (const FT::State & s ACE_ENV_ARG_DECL) ACE_THROW_SPEC ((CORBA::SystemException, FT::InvalidState)) { #if defined(FT_TEST_LACKS_STATE) ACE_THROW ( FT::InvalidState () ); #else // FT_TEST_LACKS_STATE KEVORKIAN(BEFORE_SET_STATE, set_state) long counter = loadLong(s, 0); store(counter); KEVORKIAN(AFTER_SET_STATE, set_state) #endif // FT_TEST_LACKS_STATE } void FT_TestReplica_i::tao_update_object_group ( const char * iogr, PortableGroup::ObjectGroupRefVersion version, CORBA::Boolean is_primary ACE_ENV_ARG_DECL ) ACE_THROW_SPEC ((CORBA::SystemException)) { ACE_UNUSED_ARG (iogr); ACE_UNUSED_ARG (version); ACE_UNUSED_ARG (is_primary); ACE_THROW (CORBA::NO_IMPLEMENT()); } ////////////////////////////// // implement FT_TEST::Replica void FT_TestReplica_i::set (CORBA::Long value ACE_ENV_ARG_DECL) ACE_THROW_SPEC ((CORBA::SystemException)) { KEVORKIAN(BEFORE_STATE_CHANGE, set) long counter = value; store(counter); KEVORKIAN(BEFORE_REPLY, set) } CORBA::Long FT_TestReplica_i::increment (CORBA::Long delta ACE_ENV_ARG_DECL) ACE_THROW_SPEC ((CORBA::SystemException)) { KEVORKIAN_RETURN(BEFORE_STATE_CHANGE, increment, 0) long counter = load (); counter += delta; store (counter); KEVORKIAN_RETURN(BEFORE_REPLY, increment, 0) return counter; } CORBA::Long FT_TestReplica_i::get (ACE_ENV_SINGLE_ARG_DECL) ACE_THROW_SPEC ((CORBA::SystemException)) { KEVORKIAN_DURING_RETURN(get, 0) long counter = load (); return counter; } CORBA::Long FT_TestReplica_i::counter (ACE_ENV_SINGLE_ARG_DECL) ACE_THROW_SPEC ((CORBA::SystemException)) { KEVORKIAN_DURING_RETURN([get]counter, 0) long counter = load (); return counter; } void FT_TestReplica_i::counter (CORBA::Long counter ACE_ENV_ARG_DECL) ACE_THROW_SPEC ((CORBA::SystemException)) { KEVORKIAN(BEFORE_STATE_CHANGE, [set]counter) store (counter); KEVORKIAN(BEFORE_REPLY, [set]counter) } void FT_TestReplica_i::die (FT_TEST::TestReplica::Bane when ACE_ENV_ARG_DECL) ACE_THROW_SPEC ((CORBA::SystemException)) { ACE_OS::fprintf (stdout, "%s@%s#%lu Received death threat: %d\n", name_.c_str(), this->factory_->location(), this->factory_id_, when); this->death_pending_ = when; KEVORKIAN(RIGHT_NOW, die) } void FT_TestReplica_i::shutdown (ACE_ENV_SINGLE_ARG_DECL_NOT_USED) ACE_THROW_SPEC ((CORBA::SystemException)) { ACE_OS::fprintf (stdout, "%s@%s#%lu Shut down requested\n", name_.c_str(), this->factory_->location(), this->factory_id_); this->death_pending_ = FT_TEST::TestReplica::CLEAN_EXIT; } ////////////////////////////////////////////// // FT_TestReplica_i public non-CORBA interface int FT_TestReplica_i::idle (int & result ACE_ENV_ARG_DECL) { int quit = 0; if (this->death_pending_ == FT_TEST::TestReplica::WHILE_IDLE) { ACE_ERROR ((LM_ERROR, "%s@%s#%d: Simulated fault WHILE_IDLE", this->name_.c_str(), this->factory_->location(), static_cast (this->factory_id_ ) )); this->poa_->deactivate_object (this->object_id_.in () ACE_ENV_ARG_PARAMETER); result = 0; quit = 1; } else if (this->death_pending_ == FT_TEST::TestReplica::CLEAN_EXIT) { this->poa_->deactivate_object (this->object_id_.in () ACE_ENV_ARG_PARAMETER); result = 0; quit = 1; } return quit; } void FT_TestReplica_i::request_quit() { this->death_pending_ = FT_TEST::TestReplica::WHILE_IDLE; } void FT_TestReplica_i::store(long counter) { FILE * f = ACE_OS::fopen("Persistent.dat", ACE_TEXT("w")); if(f != 0) { unsigned char* buffer = 0; ACE_NEW (buffer, unsigned char [sizeof(long)]); storeLong(buffer, 0, counter); ACE_OS::fwrite(buffer, 1, sizeof(long), f); ACE_OS::fclose(f); if (this->verbose_) { ACE_OS::fprintf (stdout, "%s@%s#%lu :%ld\n", name_.c_str(), this->factory_->location(), this->factory_id_, counter); } delete[] buffer; buffer = 0; } } long FT_TestReplica_i::load () { long counter = 0; FILE * f = ACE_OS::fopen("Persistent.dat",ACE_TEXT("r")); if(f != 0) { unsigned char buffer[sizeof(long)]; ACE_OS::fread(buffer, 1, sizeof(long), f); ACE_OS::fclose(f); counter = loadLong(buffer, 0); } return counter; }