/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */

/*
 *  Copyright (C) 2008-2009 OMC Denmark ApS.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "server.h"
#include "get_lorica.h"
#include "idl/BrutusLogOnC.h"
#include "utils/globals.h"
#include "utils/logging.h"
#include "utils/fileops.h"
#include "utils/poa_utils.h"

#ifdef BRUTUS_HAS_ESELLERATE
#include "esellerate/esellerate_keys.h"
#include <Validate Static Library/validate.h>
#endif

#include <tao/EndpointPolicy/IIOPEndpointValue_i.h>
#include <tao/EndpointPolicy/EndpointPolicy.h>
#include <tao/PortableServer/Servant_Base.h>
#include <tao/Messaging/Messaging.h>
#include <tao/TimeBaseC.h>
#include <tao/ORB_Core.h>

#include <ace/Signal.h>
#include <ace/OS_NS_stdio.h>
#include <ace/OS_NS_unistd.h>
#include <ace/OS_NS_fcntl.h>
#include <ace/Service_Gestalt.h>
#include <ace/Time_Value.h>

#include <atlbase.h>

BRUTUS::BrutusServer* BRUTUS::BrutusServer::this_ = NULL;


template<typename T>
static inline typename T::_ptr_type resolve_init(CORBA::ORB_ptr Orb,
                                                 const char *Name)
{
        std::string ref(Name);

        CORBA::Object_var obj = CORBA::Object::_nil();
        try {
                obj = Orb->resolve_initial_references(Name);
        }
        catch (const CORBA::ORB::InvalidName &e) {
                ACE_DEBUG((LM_CRITICAL, ACE_TEXT("<%T > %N:%l - %s\n"), e._info().c_str()));
                throw;
        }
        catch (const CORBA::Exception &e) {
                ACE_DEBUG((LM_CRITICAL, ACE_TEXT("<%T > %N:%l - %s\n"), e._info().c_str()));
                throw;
        }
        catch (...) {
                BRUTUS_LOG_CRITICAL("Unknown C++ exception");
                throw;
        }
        if (CORBA::is_nil(obj.in())) {
                BRUTUS_LOG_CRITICAL("Could not resolve initial reference");
                throw 0;
        }

        typename T::_var_type retval = T::_nil();
        try {
                retval = T::_narrow(obj.in());
        }
        catch (const CORBA::Exception &e) {
                ACE_DEBUG((LM_CRITICAL, ACE_TEXT("<%T > %N:%l - %s\n"), e._info().c_str()));
                throw;
        }
        catch (...) {
                BRUTUS_LOG_CRITICAL("Unknown C++ exception");
                throw;
        }
        if (CORBA::is_nil(retval.in())) {
                BRUTUS_LOG_CRITICAL("Could not narrow");
                throw 0;
        }

        return retval._retn();
}

// Will check for and if possible enable required privileges.
// Returns false on error, true otherwise.
static bool 
SetPrivilege(LPCTSTR lpszPrivilege,  // name of privilege to enable/disable
             bool bEnablePrivilege)  // to enable or disable privilege
{
        TOKEN_PRIVILEGES tp;
        LUID luid;

        if (!LookupPrivilegeValue(NULL,            // lookup privilege on local system
                                  lpszPrivilege,   // privilege to lookup
                                  &luid)) {        // receives LUID of privilege
                BRUTUS_LOG_CRITICAL("LookupPrivilegeValue failed");
                return false;
        }

        tp.PrivilegeCount = 1;
        tp.Privileges[0].Luid = luid;
        if (bEnablePrivilege)
                tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
        else
                tp.Privileges[0].Attributes = 0;

        // Enable the privilege or disable all privileges.
        HANDLE this_process = NULL;
        if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &this_process)) {
                BRUTUS_LOG_CRITICAL("OpenProcessToken failed");
                return false;
        }
        if (!AdjustTokenPrivileges(this_process,
                                   FALSE,
                                   &tp,
                                   sizeof(TOKEN_PRIVILEGES),
                                   (PTOKEN_PRIVILEGES)NULL,
                                   (PDWORD)NULL)) {
                CloseHandle(this_process);
		BRUTUS_LOG_CRITICAL("AdjustTokenPrivileges failed");
                return false;
        }
        CloseHandle(this_process);

        if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) {
                BRUTUS_LOG_CRITICAL("The token does not have the specified privilege");
                return false;
        }

        return true;
}

static bool
check_privileges(void)
{
        bool privs_ok = true;

        if (!SetPrivilege(SE_TCB_NAME, true)) {
                privs_ok = false;
                BRUTUS_LOG_CRITICAL("Enable SE_TCB_NAME (Act as part of the operating system) failed");
        }
        if (!SetPrivilege(SE_CHANGE_NOTIFY_NAME, true)) {
                privs_ok = false;
                BRUTUS_LOG_CRITICAL("Enable SE_CHANGE_NOTIFY_NAME (Bypass traverse checking) failed");
        }
        if (!SetPrivilege(SE_ASSIGNPRIMARYTOKEN_NAME, true)) { // check early so that we can refuse to start
                privs_ok = false;
                BRUTUS_LOG_CRITICAL("Enable SE_ASSIGNPRIMARYTOKEN_NAME (Replace a process level token) failed");
        } else
                SetPrivilege(SE_ASSIGNPRIMARYTOKEN_NAME, false); // we actually don't need this privelege in this process

        if (!privs_ok) {
                BRUTUS_LOG_CRITICAL("One or more required process privileges may be missing. These must be assigned for your Brutus Server to work. Please see previous log entries for potential missing privileges");
        } else
                BRUTUS_LOG_INF("Privileges OK");

        return privs_ok;
}

static CORBA::ORB_ptr 
create_orb(const char * const debug_level,
           int argc,
           char **argv)
{
        // sanity checks
        if (!argc)
                return CORBA::ORB::_nil();
        if (!*argv)
                return CORBA::ORB::_nil();
        
        long dbg_lvl = debug_level ? strtol(debug_level, NULL, 10) : 0;
        if (0 > dbg_lvl)
                dbg_lvl = 0;

        CORBA::ORB_var orb = CORBA::ORB::_nil();
        int init_argc = argc + 8 + (dbg_lvl ? 7 : 0);
        char **init_argv = (char**)malloc(sizeof(char*) * (init_argc));
        if (!init_argv)
                return CORBA::ORB::_nil();
        memset((void*)init_argv, 0, init_argc);

        // copy the original arguments
        memcpy((void*)init_argv, (void*)argv, sizeof(char*) * (argc));

        // Default Brutus Server endpoint
        init_argv[argc] = "-ORBListenEndpoints";
        init_argv[argc+1] = "iiop://1.2@localhost:2003"; // ::BRUTUS::BrutusLogOn::BRUTUS_DEFAULT_PORT

        init_argv[argc+2] = "-ORBDottedDecimalAddresses";
        init_argv[argc+3] = "1";

        init_argv[argc+4] = "-ORBObjRefStyle"; 
        init_argv[argc+5] = "IOR";
        
        init_argv[argc+6] = "-ORBSvcConf"; 
        init_argv[argc+7] = SERVER_ORB_SVC_CONF;


        if (dbg_lvl) {
                init_argv[argc+8] =  "-ORBDebug";

                init_argv[argc+9] = "-ORBDebugLevel";
                init_argv[argc+10] = (char*)debug_level;

                init_argv[argc+11] =  "-ORBVerboseLogging";
                init_argv[argc+12] = "1";

                init_argv[argc+13] =  "-ORBLogFile";
                init_argv[argc+14] = LOG_DIR"brutus-server-corba.log";
        }

        // initialize the ORB
        orb = CORBA::ORB_init(init_argc, init_argv, "com.42tools.brutus.server");
        free(init_argv);

        return orb._retn();
}


static CORBA::ORB_ptr
init_orb(const long giop_timeout,
         const char * const debug_level,
         int argc, 
         ACE_TCHAR *argv[])
{ 
        CORBA::ORB_var orb = create_orb(debug_level, argc, argv);
        
        // Set the RelativeRoundtripTimeout value to catch misbehaving subsystem components
        const long time_out = giop_timeout; // defaults to 30 seconds
        TimeBase::TimeT rt_timeout = time_out * 10000000; // in 100 nanosecond units
        ::CORBA::Any rt_timeout_as_any;
        ::CORBA::PolicyList policy_list(1);

        rt_timeout_as_any <<= rt_timeout;
        policy_list.length(1);
        policy_list[0] = orb->create_policy(Messaging::RELATIVE_RT_TIMEOUT_POLICY_TYPE,
                                            rt_timeout_as_any);

        // Apply the policy at the ORB level using the ORBPolicyManager.
        ::CORBA::Object_var obj = orb->resolve_initial_references("ORBPolicyManager");
        ::CORBA::PolicyManager_var policy_manager = ::CORBA::PolicyManager::_narrow(obj.in());
        policy_manager->set_policy_overrides(policy_list, ::CORBA::SET_OVERRIDE);

        policy_list[0]->destroy();

        return orb._retn();
}

static bool
create_server_svn_file(void)
{
        bool retv = false;
        create_file(false, SERVER_ORB_SVC_CONF);

        std::ofstream svc_conf(SERVER_ORB_SVC_CONF, ifstream::trunc | ifstream::out);
        if (!svc_conf) {
                BRUTUS_LOG_CRITICAL("Configuration error: Could not create server TAO Service Configuration file");
                goto exit;
        }

        svc_conf << "static Server_Strategy_Factory \"-ORBConcurrency thread-per-connection -ORBPOALock thread\"\n";
	svc_conf << "static Resource_Factory \"-ORBNativeCharCodeset 0x05010001 -ORBNativeWCharCodeset 0x00010109\"\n"; // UTF-8 and UTF-16
        svc_conf.close();

        retv = true;

exit:
        return retv;
}

static bool
create_proxy_svn_file(void)
{
        bool retv = false;
        create_file(false, PROXY_ORB_SVC_CONF);

        std::ofstream svc_conf(PROXY_ORB_SVC_CONF, ifstream::trunc | ifstream::out);
        if (!svc_conf) {
                BRUTUS_LOG_CRITICAL("Configuration error: Could not create proxy TAO Service Configuration file");
                goto exit;
        }

        svc_conf << "static Server_Strategy_Factory \"-ORBConcurrency thread-per-connection -ORBPOALock thread\"\n";
	svc_conf << "static Resource_Factory \"-ORBNativeCharCodeset 0x05010001 -ORBNativeWCharCodeset 0x00010109\"\n"; // UTF-8 and UTF-16
        svc_conf.close();

        retv = true;

exit:
        return retv;
}

BRUTUS::BrutusServer::BrutusServer(const bool debug,
                                   int argc,
                                   ACE_TCHAR *argv[])
        : pid_file_(),
          ior_file_(),
          local_pid_file_("server.pid"),
          local_ior_file_("server.ior"),
          must_shutdown_(false),
          debug_(debug),
          argc_(argc),
          argv_(argv)
{
        brutus_logon_ = ::BRUTUS::BrutusLogOn::_nil();
        reference_mapper_ = ::Lorica::ReferenceMapper::_nil();
        logon_mapped_ = ::CORBA::Object::_nil();
        logon_mapped_secure_ = ::CORBA::Object::_nil();
}

void
BRUTUS::BrutusServer::shutdown(void)
{
        this->must_shutdown_ = true;
}

int
BRUTUS::signal_handler(int signum)
{
        /// Need to make this thread safe
        if (BRUTUS::BrutusServer::this_ != 0)
                BRUTUS::BrutusServer::this_->shutdown();

        ACE_UNUSED_ARG(signum);

        return 0;
};

bool
BRUTUS::BrutusServer::setup_shutdown_handler(void)
{
        ACE_Sig_Set sigset;

        // Register signal handlers.
        sigset.sig_add(SIGINT);
        sigset.sig_add(SIGUSR1);
        sigset.sig_add(SIGUSR2);
        sigset.sig_add(SIGTERM);
        sigset.sig_add(SIGABRT);
        sigset.sig_add(SIGFPE);
        sigset.sig_add(SIGILL);
        sigset.sig_add(SIGSEGV);

        // Register the <handle_signal> method to process all the signals in
        // <sigset>.
        ACE_Sig_Action sa(sigset, (ACE_SignalHandler)BRUTUS::signal_handler);
        ACE_UNUSED_ARG(sa);

        return true;
}

int
BRUTUS::BrutusServer::open(void *args)
{
        int config_load = 0;
        BRUTUS::Config conf;
        ACE_TCHAR *config_file = NULL;
        int corba_debug_level = 0;

        if (args == 0)
                return 0;
        config_file = reinterpret_cast<ACE_TCHAR*>(args);

        // load configuration
        config_load = conf.load(config_file);
        if (config_load) {
                if (config_load > 0)
                        ACE_DEBUG((LM_CRITICAL, ACE_TEXT("<%T >%N:%l - Configuration error: Error in configuration file at line %d"), config_load));
                else
                        ACE_DEBUG((LM_CRITICAL, ACE_TEXT("<%T >%N:%l - Configuration error: Could not open %s"), config_file));

                return 0;
        }

        try {
                this->configure(conf);
        }
        catch (const BRUTUS::BrutusServer::InitError &) {
                BRUTUS_LOG_CRITICAL("Configuration failed");
                return 0;
        }

        return 1;
}

static inline FILE*
get_file(const char *filename)
{
        ACE_HANDLE file_fd = ACE_INVALID_HANDLE;
        FILE *file = NULL;

        file_fd = ACE_OS::open(filename, O_CREAT | O_WRONLY | O_TRUNC);
        if (ACE_INVALID_HANDLE == file_fd) {
                ACE_DEBUG((LM_ERROR, "<%T >%N:%l - could not ACE_OS::open %s\n", filename));
                return NULL;
        }

        file = ACE_OS::fdopen(file_fd, "w");
        if (!file) {
                int err = 0;

                _get_errno(&err); 

		char msg_[512] = { '\0' };
		sprintf_s(msg_, sizeof(msg_), "could not ACE_OS::fdopen %s - error = %s", filename, strerror(err));
                ACE_DEBUG((LM_ERROR, "%N:%l - %s\n", msg_));
                ACE_OS::close(file_fd);
        }

        return file;
}

void
BRUTUS::BrutusServer::configure(BRUTUS::Config & config)
        throw (InitError)
{
        ::BRUTUS_BrutusLogOn_i *brutus_logon_impl = NULL;
        ::CORBA::Object_var obj = ::CORBA::Object::_nil();
        ::PortableServer::ObjectId_var obj_oid;
        char *ior = NULL;
        long giop_timeout;
        bool secure_lorica = false;
	char cwd[_MAX_PATH] = { '\0' };

	if (!GetCurrentDirectory(_MAX_PATH, cwd))
		throw InitError();

        /*
         * Read configuration
         */
#ifdef BRUTUS_HAS_ESELLERATE
	{ // check serial number
		eSellerate_DaysSince2000 esel_today = eSellerate_Today();
		eSellerate_DaysSince2000 esel_trial_days = 0;
		eSellerate_DaysSince2000 esel_server_days = 0;
		
		BRUTUS_LOG_INF("Validating server license");

		eSellerate_String serial_name = NULL;
		serial_name = config.get_value("SERIAL_NAME");
		if (!serial_name) {
			BRUTUS_LOG_CRITICAL("No serial name");
			goto esellerate_fail;
		}
		
		eSellerate_String serial_number = NULL;
		serial_number = config.get_value("SERIAL_NUMBER");
		if (!serial_name) {
			free(serial_name);
			BRUTUS_LOG_CRITICAL("No serial number");
			goto esellerate_fail;
		}
		
		esel_trial_days = eSellerate_ValidateSerialNumber(serial_number, serial_name, NULL, ESELLERATE_TRIAL_KEY);
		esel_server_days = eSellerate_ValidateSerialNumber(serial_number, serial_name, NULL, ESELLERATE_SERVER_KEY);
		free(serial_name);
		free(serial_number);

		if (!esel_trial_days && !esel_server_days) {
			BRUTUS_LOG_CRITICAL("Invalid serial name or number");
			goto esellerate_fail;
		}

		if (esel_server_days > 0)
			goto esellerate_ok;

		if (esel_trial_days < esel_today) {
			BRUTUS_LOG_CRITICAL("Your trial license has expired");
			goto esellerate_fail;
		} else {
			if (esel_trial_days == esel_today) {
				BRUTUS_LOG_INF("Trial license validated OK: This day remaining");
			} else {
				char msg[128] = {0};
				sprintf_s(msg, sizeof(msg), "Trial license validated OK: %d days remaining", esel_trial_days - esel_today);
				BRUTUS_LOG_INF(msg);
			}
		}
	}
esellerate_ok:
	BRUTUS_LOG_INF("Brutus Server running under proprietary terms");
esellerate_fail:
#else
	BRUTUS_LOG_INF("Brutus Server running as free software - Please see the file COPYING for details.");
#endif // BRUTUS_HAS_ESELLERATE


        char *giop_timeout_str = NULL;
        giop_timeout_str = config.get_value("CLIENT_GIOP_TIMEOUT");
        if (giop_timeout_str)
                giop_timeout = strtol(giop_timeout_str, NULL, 10);
        else
                giop_timeout = 30;
        free(giop_timeout_str);
        if ((giop_timeout <= 0) || (giop_timeout > 86400))
                giop_timeout = 86400;

        try {
                // This should be OK even if multiple copies of BrutusServer
                // get created as they all create the same ORB instance
                // and therefore the single ORB instance will get shutdown.
                BRUTUS::BrutusServer::this_ = this;

                this->pid_file_ = "brutus.pid";
                this->ior_file_ = "brutus.ior";

                this->setup_shutdown_handler();

		BRUTUS_LOG_INF("Checking privileges");
                if (!check_privileges())
                        throw InitError();

		BRUTUS_LOG_INF("Creating Server TAO Service Configuration file");
                if (!create_server_svn_file())
                        throw InitError();

		BRUTUS_LOG_INF("Creating Proxy TAO Service Configuration file");
                if (!create_proxy_svn_file())
                        throw InitError();

		BRUTUS_LOG_INF("Creating server ORB");
                {
                        char *corba_dbg_lvl_str = config.get_value("CORBA_DEBUG_LEVEL");
                        this->orb_ = init_orb(giop_timeout, corba_dbg_lvl_str, this->argc_, this->argv_);
                        if (corba_dbg_lvl_str)
                                free(corba_dbg_lvl_str);
                }
                if (CORBA::is_nil(this->orb_.in())) {
			BRUTUS_LOG_CRITICAL("Could not create the ORB");
                        throw InitError();
                }


                /////////////////////////////////////////
                //                POAs                 //
                /////////////////////////////////////////

                try {
                        this->root_poa_ = resolve_init<PortableServer::POA>(this->orb_.in(), "RootPOA");
                }
                catch (CORBA::Exception & e) {
                        ACE_DEBUG((LM_CRITICAL, ACE_TEXT("<%T > %N:%l - %s\n"), e._info().c_str()));
                        throw InitError();
                }
                catch (...) {
                        throw InitError();
                }
                if (CORBA::is_nil(this->root_poa_.in())) {
			BRUTUS_LOG_CRITICAL("Could not create root POA");
                        throw InitError();
                }

                // server root poa manager
                this->root_poa_manager_ = this->root_poa_->the_POAManager();
                if (CORBA::is_nil(this->root_poa_manager_.in())) {
			BRUTUS_LOG_CRITICAL("Could not create POAManager");
                        throw InitError();
                }
                this->root_poa_manager_->activate();

                // factory server poa
                this->factory_poa_ = create_poa((const char*)"FACTORY_POA", PortableServer::POAManager::_nil(), this->root_poa_);
                if (CORBA::is_nil(this->factory_poa_.in())) {
			BRUTUS_LOG_CRITICAL("Could not create factory POA");
                        throw InitError();
                }

                // factory server poa manager
                this->factory_poa_manager_ = this->factory_poa_->the_POAManager();
                if (CORBA::is_nil(this->factory_poa_manager_.in())) {
			BRUTUS_LOG_CRITICAL("Could not create factory POAManager");
                        throw InitError();
                }
                this->factory_poa_manager_->activate();



                /////////////////////////////////////
		//     Set MMP path in registry    //
                /////////////////////////////////////
		{
			DWORD disposition = 0;
			CRegKey *reg = new CRegKey();
			if (!reg) {
				BRUTUS_LOG_CRITICAL("No memory");
				throw InitError();
			}
			reg->m_hKey = NULL;

			long reg_retv = reg->Create(HKEY_LOCAL_MACHINE,
						    "Software\\Microsoft\\Windows Messaging Subsystem\\",
						    REG_NONE,
						    REG_OPTION_NON_VOLATILE,
						    KEY_WRITE | KEY_READ,
						    NULL,
						    &disposition);
			switch (disposition) {
			case REG_CREATED_NEW_KEY :
				break;
			case REG_OPENED_EXISTING_KEY :
				break;
			default :
				BRUTUS_LOG_CRITICAL("Unknown disposition for HKEY_LOCAL_MACHINE/Software/Microsoft/Windows Messaging Subsystem");
			}
			if (reg_retv != ERROR_SUCCESS) {
				BRUTUS_LOG_CRITICAL("Could not open HKEY_LOCAL_MACHINE/Software/Microsoft/Windows Messaging Subsystem");
				reg->Close();
				delete reg;
				throw InitError();
			}

			char mmp_dir[_MAX_PATH] = { '\0' };
			if (!GetCurrentDirectory(sizeof(mmp_dir), mmp_dir))
				throw InitError();
			strcat_s(mmp_dir, sizeof(mmp_dir), "\\");
			strcat_s(mmp_dir, sizeof(mmp_dir), MMP_DIR);
			mmp_dir[strlen(mmp_dir) - 1] = '\0';

			reg_retv = reg->SetStringValue("ProfileDirectory",
						       mmp_dir,
						       REG_SZ);
			reg->Close();
			if (reg_retv != ERROR_SUCCESS) {
				BRUTUS_LOG_CRITICAL("Could not set ProfileDirectory");
				delete reg;
				throw InitError();
			}

			delete reg;
		}

                /////////////////////////////////////
                //       Create factory object     //
                /////////////////////////////////////

                try {
                        brutus_logon_impl = new BRUTUS_BrutusLogOn_i(cwd,
								     this->factory_poa_.in(),
                                                                     this->orb_.in());
                }
                catch (std::bad_alloc &) {
			BRUTUS_LOG_CRITICAL("No memory");
                        brutus_logon_impl = NULL;
                }
                catch (...) {
			BRUTUS_LOG_CRITICAL("Unknown C++ exception");
                        brutus_logon_impl = NULL;
                }
                if (!brutus_logon_impl)
                        throw InitError();

                obj_oid = this->factory_poa_->activate_object(brutus_logon_impl);
                obj = this->factory_poa_->id_to_reference(obj_oid);
                this->brutus_logon_ = ::BRUTUS::BrutusLogOn::_narrow(obj);
                ior = this->orb_->object_to_string(this->brutus_logon_.in());

                ////////////////////////////////////////////////////////////////////
                //    Register the factory object in the session ORB IOR table    //
                ////////////////////////////////////////////////////////////////////

                // Get a reference to the IOR Table
                try {
                        this->ior_table_ = resolve_init<IORTable::Table>(this->orb_.in(), "IORTable");
                }
                catch (CORBA::Exception & e) {
                        ACE_DEBUG((LM_CRITICAL, ACE_TEXT("<%T > %N:%l - %s\n"), e._info().c_str()));
                        throw InitError();
                }
                catch (...) {
                        BRUTUS_LOG_CRITICAL("Unknown C++ exception");
                        throw InitError();
                }
                if (CORBA::is_nil(this->ior_table_.in())) {
                        BRUTUS_LOG_CRITICAL("Could not get IORTable");
                        throw InitError();
                }

                // Bind the stringified IOR in the IOR Table
                this->ior_table_->bind(::BRUTUS::BrutusLogOn::IOR_TABLE_KEY, ior);
		CORBA::string_free(ior);
		ior = NULL;

                /////////////////////////////////////////////////////////
                //    Additionally register BrutusLogOn with Lorica    //
                /////////////////////////////////////////////////////////

                try {
                        this->reference_mapper_ = get_lorica(this->orb_.in(), secure_lorica);
                }
                catch (const CORBA::Exception &) {
                        BRUTUS_LOG_CRITICAL("CORBA exception caught when getting reference to Lorica");
                        throw;
                }
                catch (...) {
                        BRUTUS_LOG_CRITICAL("Unknown exception caught when getting reference to Lorica");
                        throw;
                }

                if (CORBA::is_nil(this->reference_mapper_.in())) {
                        BRUTUS_LOG_INF("Lorica not available");
                        goto done_mapping;
                }
 
                try {
                        if (secure_lorica) {
                                this->logon_mapped_secure_ = this->reference_mapper_->as_secure_server(this->brutus_logon_.in(),
												       ::BRUTUS::BrutusLogOn::IOR_TABLE_KEY,
												       ::Lorica::ServerAgent::_nil());
				if (CORBA::is_nil(this->logon_mapped_secure_.in())) {
					BRUTUS_LOG_CRITICAL("Lorica reference mapper could not map BrutusLogOn securely");
					goto done_mapping;
				}
			} else {
				this->logon_mapped_ = this->reference_mapper_->as_server(this->brutus_logon_.in(),
											 ::BRUTUS::BrutusLogOn::IOR_TABLE_KEY,
											 ::Lorica::ServerAgent::_nil());
				if (CORBA::is_nil(this->logon_mapped_.in())) {
					BRUTUS_LOG_CRITICAL("Lorica reference mapper could not map BrutusLogOn");
					goto done_mapping;
				}

			}
                }
                catch (const CORBA::Exception &e) {
                        ACE_DEBUG((LM_CRITICAL, ACE_TEXT("<%T > %N:%l - %s\n"), e._info().c_str()));
                }
                catch (...) {
                        BRUTUS_LOG_CRITICAL("Unknown exception caught when mapping BrutusLogOn");
                }

        done_mapping:
                ;
        }
        catch (CORBA::Exception & e) {
                ACE_DEBUG((LM_CRITICAL, ACE_TEXT("<%T > %N:%l - %s\n"), e._info().c_str()));
                throw InitError();
        }
        catch (const BRUTUS::BrutusServer::InitError &) {
                BRUTUS_LOG_CRITICAL("Could not inititate server");
                throw;
        }
        catch (...) {
                BRUTUS_LOG_CRITICAL("Unknown C++ exception");
                throw InitError();
        }
}

BRUTUS::BrutusServer::~BrutusServer(void)
{
}

void
BRUTUS::BrutusServer::local_pid_file(const std::string& lpf)
{
        this->local_pid_file_ = lpf;
}

void
BRUTUS::BrutusServer::local_ior_file(const std::string& lif)
{
        this->local_ior_file_ = lif;
}

int
BRUTUS::BrutusServer::svc(void)
{
        factory_poa_manager_->activate();

        // Output the pid file indicating we are running
        FILE *output_file= ACE_OS::fopen(this->pid_file_.c_str(), "w");
        if (output_file == 0) {
                ACE_ERROR_RETURN((LM_ERROR,
                                  "<%T > %N:%l - cannot open output file for writing PID: %s\n",
                                  this->pid_file_.c_str()),
                                 EXIT_FAILURE);
        }
        ACE_OS::fprintf(output_file, "%d\n", ACE_OS::getpid());
        ACE_OS::fclose(output_file);

        while (!this->must_shutdown_) {
                ACE_Time_Value timeout(1,0);
                this->orb_->run(timeout);
        }
        ACE_OS::unlink (this->pid_file_.c_str());

	// release mapped object resources in Lorica
	if (!CORBA::is_nil(this->logon_mapped_.in())) {
		try {
			this->reference_mapper_->remove_server(this->logon_mapped_.in());
		}
		catch (const CORBA::Exception &e) {
			BRUTUS_LOG_CRITICAL(e._info().c_str());
		}
		catch (...) {
			BRUTUS_LOG_CRITICAL("Unknown C++ exception");
		}
	}
	if (!CORBA::is_nil(this->logon_mapped_secure_.in())) {
		try {
			this->reference_mapper_->remove_server(this->logon_mapped_secure_.in());
		}
		catch (const CORBA::Exception &e) {
			BRUTUS_LOG_CRITICAL(e._info().c_str());
		}
		catch (...) {
			BRUTUS_LOG_CRITICAL("Unknown C++ exception");
		}
	}

        return EXIT_SUCCESS;
}
