/*
* Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:    
* This file was autogenerated by rpcgen, but should be modified by the developer.
* Make sure you don't use the -component_mod flag in future or this file will be overwritten.
* Mon Oct 06 12:02:04 2003
* System Includes
*
*/





#include <stdio.h>
#include <signal.h>
#ifndef WIN32
#include <unistd.h>
#include <net/if.h>
#endif


/****************************************************************************************
 * 
 * Local Includes
 * 
 ***************************************************************************************/
#include "CSvcFacontroller.h"
#include "CSFacontroller.h"


/****************************************************************************************
 * 
 * Definition
 * 
 ***************************************************************************************/
#define TEMPLATE_CONFIG_FILE			"dynfad.template.conf"
#define MOBILE_AGENT_COMMAND_LINE		"./dynfad --fg --debug --config "
#define MAXCOMMANDLINELENGTH			(31 + 256 + 1)
#define MAXTUNNELS                      32
#define MAXINTERFACECONFIGENTRY			(IFNAMSIZ + 128)
#define CONFIGCOUNT						16


/*******************************************************************************
 *
 * Macro Functions
 *
 ******************************************************************************/


/****************************************************************************************
 * 
 * Implementation
 * 
 ***************************************************************************************/
CSFacontroller::CSFacontroller()
{
	iDynamicsCallTimeout = -1;
	iAgentProcess = NULL;
}

CSFacontroller::~CSFacontroller()
{
	assert( iAgentProcess == NULL );
}

int CSFacontroller::GetKey()
{
	return iKey;
}

void CSFacontroller::SetKey( int aKey )
{
	iKey = aKey;
}


/****************************************************************************************
 * 
 * PUBLIC FUNCTION: cstr_createagent
 * 
 ***************************************************************************************/
TResult CSFacontroller::cstr_createagent( void )
{
	TResult rv;
	TDCFError terr, terr_a[CONFIGCOUNT];
	TInterfaceAliasError ierr;
	TStartupInfo startup_info;
	CIntegerAllocator *ialloc;
	char dynamics_config[MAXINTERFACECONFIGENTRY];
	string interface_name, interface_address;
	int errcode, i;

	// initialise the result
	rv.iServiceResult = ERR_NONE;
	rv.iSubComponentResult = 0;
	rv.iData0 = 0;
	rv.iData1 = 0;

	// get an address for the new interface alias
	ialloc = CSvcFacontroller::GetIntegerAllocator();
	assert( ialloc != NULL );
	iInterfaceHostAddress = ialloc->AllocateInteger();
	if( iInterfaceHostAddress == -1 ) {
	  rv.iServiceResult = ERR_NO_MORE_INTERFACES;
	  return rv;
	}

	// create a local copy of the configuration file
	terr = iDynamicsConfigFile.SetReferenceFile( TEMPLATE_CONFIG_FILE );
	if( terr != DCE_NONE ) {
	  ialloc->FreeInteger( iInterfaceHostAddress );
	  rv.iServiceResult = ERR_CONFIG_FILE_ERROR;
	  rv.iSubComponentResult = (int)terr;
	  return rv;
	}
	terr = iDynamicsConfigFile.CreateLocalCopy( &errcode );
	if( terr != DCE_NONE ) {
	  ialloc->FreeInteger( iInterfaceHostAddress );
	  rv.iServiceResult = ERR_CONFIG_FILE_ERROR;
	  rv.iSubComponentResult = (int)terr;
	  rv.iData0 = errcode;
	  return rv;
	}	  

	// create an alias interface to use
	startup_info = CSvcFacontroller::GetStartupInfo();
	ierr = iAgentInterface.CreateNewInterfaceAlias( startup_info.iBaseInterfaceIndex, startup_info.iNetworkMask, iInterfaceHostAddress, &iInterfaceIndex, &errcode );
	if( ierr != IE_NONE ) {
	  rv.iServiceResult = ERR_CREATE_INTERFACE_ERROR;
	  rv.iSubComponentResult = ierr;
	  rv.iData0 = errcode;
	  ialloc->FreeInteger( iInterfaceHostAddress );
	  iDynamicsConfigFile.RemoveLocalCopy( &errcode );
	  return rv;
	}
	ierr = iAgentInterface.GetInterfaceAddress( &interface_address );
	assert( ierr == IE_NONE );

	// set the interface name in the config file
	ierr = iAgentInterface.GetInterfaceName( &interface_name );
	snprintf( dynamics_config, MAXINTERFACECONFIGENTRY, "%s 2 -1 10", interface_name.c_str() ); 
	terr_a[0] = iDynamicsConfigFile.AddListOption( "INTERFACES_BEGIN", "INTERFACES_END", dynamics_config, &errcode );

	// set the tunnel name prefix to a unique value for this agent
	//	snprintf( dynamics_config, MAXINTERFACECONFIGENTRY, "TunnelDevice \"TUNL-%s-\"", interface_name.c_str() );
	snprintf( dynamics_config, MAXINTERFACECONFIGENTRY, "TunnelDevice \"TUNL\"" );
	terr_a[1] = iDynamicsConfigFile.SetSingleOption( "TunnelDevice", dynamics_config, &errcode );

	// set the FA addresses to the alias interface address
	snprintf( dynamics_config, MAXINTERFACECONFIGENTRY, "HighestFAIPAddress %s", interface_address.c_str() );
	terr_a[2] = iDynamicsConfigFile.SetSingleOption( "HighestFAIPAddress", dynamics_config, &errcode );

	// set the FA addresses to the alias interface address
	snprintf( dynamics_config, MAXINTERFACECONFIGENTRY, "UpperFAIPAddress %s", interface_address.c_str() );
	terr_a[3] = iDynamicsConfigFile.SetSingleOption( "UpperFAIPAddress", dynamics_config, &errcode );

	// see if any errors occured setting the config info
	for( i = 0; i < 3; i++ ) {
		if( terr_a[i] != DCE_NONE ) {
			rv.iServiceResult = ERR_CONFIG_FILE_ERROR;
			rv.iSubComponentResult = (int)terr_a[i];
			iAgentInterface.DestroyInterfaceAlias( &errcode );
			ialloc->FreeInteger( iInterfaceHostAddress );
			iDynamicsConfigFile.RemoveLocalCopy( &errcode );
			return rv;
		}
	}

	// done - success
	return rv;
}


/****************************************************************************************
 * 
 * PUBLIC FUNCTION: dstr_removeagent
 * 
 ***************************************************************************************/
int CSFacontroller::dstr_removeagent( int aArgs, int *aDeleteInstance )
{
	int rv = ERR_NONE, errcode;
	TDCFError terr;
	TInterfaceAliasError ierr;
	CIntegerAllocator *ialloc;

	// make sure that the proces isn't running
	if( iAgentProcess != NULL ) {
	  *aDeleteInstance = 0;
	  rv = ERR_INVALIDSTATE;
	  return rv;
	}

	// free the interface index
	ialloc = CSvcFacontroller::GetIntegerAllocator();
	assert( ialloc != NULL );
	ialloc->FreeInteger( iInterfaceHostAddress );

	// clean up the config file
	terr = iDynamicsConfigFile.RemoveLocalCopy( &errcode );

	// destroy the interface alias
	ierr = iAgentInterface.DestroyInterfaceAlias( &errcode );
	  
	// check for errors from the config file - delete the instance in any case
	if( terr != DCE_NONE ) {
	  rv = ERR_CONFIG_FILE_ERROR;
	  return rv;
	}

	// check for errors from the interface alias - delete the instance
	if( ierr != IE_NONE ) {
	  rv = ERR_DESTROY_INTERFACE_ERROR;
	  return rv;
	}

	// done - success
	return rv;
}


/****************************************************************************************
 * 
 * PUBLIC FUNCTION: startmobileagent
 * 
 ***************************************************************************************/
TResult CSFacontroller::startmobileagent( TStartAgentRequest aArgs )
{
	TResult rv;
	int errcode;
	TCAProcessError perr;
	char command_line_str[MAXCOMMANDLINELENGTH];
	TDCFError terr;

	// initialise the result
	rv.iServiceResult = ERR_NONE;
	rv.iSubComponentResult = 0;
	rv.iData0 = 0;
	rv.iData1 = 0;

	// check that there is currently no process
	if( iAgentProcess != NULL ) {
		rv.iServiceResult = ERR_INVALIDSTATE;
		return rv;
	}

	// do some semantic checking of the params
	if( (aArgs.iSolicitationMode < -1) || (aArgs.iSolicitationMode > 1) ) {
		rv.iServiceResult = ERR_INVALIDARG;
		rv.iData0 = 3;
		return rv;
	}
	if( (aArgs.iSolicitationMode == 1) && (aArgs.iSolicitationInterval < 1) ) {
		rv.iServiceResult = ERR_INVALIDARG;
		rv.iData0 = 4;
		return rv;
	}
	if( aArgs.iSolicitationMode != 1 ) {
	  aArgs.iSolicitationInterval = 1;
	}

	// add the interface name to the config file
	snprintf( command_line_str, MAXCOMMANDLINELENGTH, "%s 3 %d %d", aArgs.iLowerInterface, aArgs.iSolicitationMode, aArgs.iSolicitationInterval );
	terr = iDynamicsConfigFile.AddListOption( "INTERFACES_BEGIN", "INTERFACES_END", command_line_str, &errcode );
	if( terr != DCE_NONE ) {
		rv.iServiceResult = ERR_CONFIG_FILE_ERROR;
		rv.iSubComponentResult = (int)terr;
		return rv;
	}
	
	// create the new process object
	iAgentProcess = new CAProcess();
	assert( iAgentProcess != NULL );

	// construct the command line
	snprintf( command_line_str, MAXCOMMANDLINELENGTH, "%s%s", MOBILE_AGENT_COMMAND_LINE, iDynamicsConfigFile.GetLocalFilename() );

	// start the actual process
	perr = iAgentProcess->StartProcess( command_line_str, &errcode, false, false, false ); 
	if( perr != CAE_NONE ) {
		rv.iServiceResult = ERR_START_PROCESS_ERROR;
		rv.iSubComponentResult = (int)perr;
		delete iAgentProcess;
		iAgentProcess = NULL;
		return rv;
	}
	iLowerInterface = aArgs.iLowerInterface;

	// done - success
	rv.iServiceResult = ERR_NONE;
	return rv;
}


/****************************************************************************************
 * 
 * PUBLIC FUNCTION: stopmobileagent
 * 
 ***************************************************************************************/
TResult CSFacontroller::stopmobileagent( int aArgs )
{
	TResult rv;
	TCAProcessError perr;
	TProcessStatus pstatus;
	TDCFError terr;
	int errcode;

	// initialise the result
	rv.iServiceResult = ERR_NONE;
	rv.iSubComponentResult = 0;
	rv.iData0 = 0;
	rv.iData1 = 0;


	// if the process isn't started then invalid state
	if( iAgentProcess == NULL ) {
	  rv.iServiceResult = ERR_INVALIDSTATE;
	  return rv;
	}

	// remove the interface line added in startup
	terr = iDynamicsConfigFile.RemoveListOption( "INTERFACES_BEGIN", "INTERFACES_END", iLowerInterface.c_str(), &errcode );
	if( terr != DCE_NONE ) {
		rv.iServiceResult = ERR_CONFIG_FILE_ERROR;
		rv.iSubComponentResult = (int)terr;
		return rv;
	}

	// if the process isn't running then it has died outside the scope of this controller, clean up the state, return an error since
	// this is noteworthy and should be either expected or not happen.
	perr = iAgentProcess->GetProcessStatus( &pstatus );
	assert( perr == CAE_NONE );
	if( pstatus != PS_STARTED ) {
	  assert( (pstatus == PS_STOPPED) || (pstatus == PS_ABANDONNED) );
	  delete iAgentProcess;
	  iAgentProcess = NULL;
	  rv.iServiceResult = ERR_PROCESS_TERMINATED_OUTSIDE_SCOPE;
	  return rv;
	}

	// request the process to stop
	perr = iAgentProcess->RequestStop( SIGTERM );
	if( perr != CAE_NONE ) {
	  rv.iServiceResult = ERR_STOP_PROCESS_ERROR;
	  rv.iSubComponentResult = (int)perr;
	  return rv;
	}

	// wait for the process to stop
	perr = iAgentProcess->WaitForProcessToTerminate( -1 );
	if( perr != CAE_NONE ) {
	  rv.iServiceResult = ERR_WAIT_PROCESS_ERROR;
	  rv.iSubComponentResult = (int)perr;
	  return rv;
	}

	// remove the process
	delete iAgentProcess;
	iAgentProcess = NULL;

	// done - success
	return rv;
}


/****************************************************************************************
 * 
 * PUBLIC FUNCTION: getmobileagentstatus
 * 
 ***************************************************************************************/
TResult CSFacontroller::getmobileagentstatus( int aArgs )
{
	TResult rv;
	TCAProcessError perr;
	TProcessStatus pstatus;

	// initialise the result
	rv.iServiceResult = ERR_NONE;
	rv.iSubComponentResult = 0;
	rv.iData0 = 0;
	rv.iData1 = 0;


	// if the process doesn't exist then we return PS_INVALID
	if( iAgentProcess == NULL ) {
		rv.iData0 = PS_INVALID;
		return rv;
	}

	// otherwise just return whatever iAgentProcess->GetProcessStatus() returns
	perr = iAgentProcess->GetProcessStatus( &pstatus );
	assert( perr == CAE_NONE );
	rv.iData0 = (int)pstatus;
	return rv;
}


/****************************************************************************************
 * 
 * PUBLIC FUNCTION: setsingleoption
 * 
 ***************************************************************************************/
TResult CSFacontroller::setsingleoption( TOptionDesc aArgs )
{
	TResult rv;
	int errcode;
	TDCFError cerr;

	// initialise the result
	rv.iServiceResult = ERR_NONE;
	rv.iSubComponentResult = 0;
	rv.iData0 = 0;
	rv.iData1 = 0;

	// make sure that the process isn't running
	if( iAgentProcess != NULL ) {
		rv.iServiceResult = ERR_INVALIDSTATE;
		return rv;
	}

	// modify the config file
	cerr = iDynamicsConfigFile.SetSingleOption( aArgs.iOptionToken, aArgs.iOptionValue, &errcode );
	if( cerr != DCE_NONE ) {
		rv.iServiceResult = ERR_CONFIG_FILE_ERROR;
		rv.iSubComponentResult = (int)cerr;
		rv.iData0 = errcode;
		return rv;
	}

	// return success
	rv.iServiceResult = ERR_NONE;
	return rv;
}


/****************************************************************************************
 * 
 * PUBLIC FUNCTION: removesingleoption
 * 
 ***************************************************************************************/
TResult CSFacontroller::removesingleoption( TOptionDesc aArgs )
{
	TResult rv;
	int errcode;
	TDCFError cerr;

	// initialise the result
	rv.iServiceResult = ERR_NONE;
	rv.iSubComponentResult = 0;
	rv.iData0 = 0;
	rv.iData1 = 0;

	// make sure that the process isn't running
	if( iAgentProcess != NULL ) {
		rv.iServiceResult = ERR_INVALIDSTATE;
		return rv;
	}

	// modify the config file
	cerr = iDynamicsConfigFile.RemoveSingleOption( aArgs.iOptionToken, &errcode );
	if( cerr != DCE_NONE ) {
		rv.iServiceResult = ERR_CONFIG_FILE_ERROR;
		rv.iSubComponentResult = (int)cerr;
		rv.iData0 = errcode;
		return rv;
	}

	// return success
	rv.iServiceResult = ERR_NONE;
	return rv;
}


/****************************************************************************************
 * 
 * PUBLIC FUNCTION: addlistoption
 * 
 ***************************************************************************************/
TResult CSFacontroller::addlistoption( TOptionDesc aArgs )
{
	TResult rv;
	int errcode;
	TDCFError cerr;

	// initialise the result
	rv.iServiceResult = ERR_NONE;
	rv.iSubComponentResult = 0;
	rv.iData0 = 0;
	rv.iData1 = 0;

	// make sure that the process isn't running
	if( iAgentProcess != NULL ) {
		rv.iServiceResult = ERR_INVALIDSTATE;
		return rv;
	}

	// modify the config file
	cerr = iDynamicsConfigFile.AddListOption( aArgs.iOptionBlockStart, aArgs.iOptionBlockEnd, aArgs.iOptionValue, &errcode );
	if( cerr != DCE_NONE ) {
		rv.iServiceResult = ERR_CONFIG_FILE_ERROR;
		rv.iSubComponentResult = (int)cerr;
		rv.iData0 = errcode;
		return rv;
	}

	// return success
	rv.iServiceResult = ERR_NONE;
	return rv;
}


/****************************************************************************************
 * 
 * PUBLIC FUNCTION: removelistoption
 * 
 ***************************************************************************************/
TResult CSFacontroller::removelistoption( TOptionDesc aArgs )
{
	TResult rv;
	int errcode;
	TDCFError cerr;

	// initialise the result
	rv.iServiceResult = ERR_NONE;
	rv.iSubComponentResult = 0;
	rv.iData0 = 0;
	rv.iData1 = 0;

	// make sure that the process isn't running
	if( iAgentProcess != NULL ) {
		rv.iServiceResult = ERR_INVALIDSTATE;
		return rv;
	}

	// modify the config file
	cerr = iDynamicsConfigFile.RemoveListOption( aArgs.iOptionBlockStart, aArgs.iOptionBlockEnd, aArgs.iOptionToken, &errcode );
	if( cerr != DCE_NONE ) {
		rv.iServiceResult = ERR_CONFIG_FILE_ERROR;
		rv.iSubComponentResult = (int)cerr;
		rv.iData0 = errcode;
		return rv;
	}

	// return success
	rv.iServiceResult = ERR_NONE;
	return rv;
}


/****************************************************************************************
 * 
 * PUBLIC FUNCTION: getstatus
 * 
 ***************************************************************************************/
TFaStatusInfo CSFacontroller::getstatus( int aArgs )
{
	TFaStatusInfo rv;
	TDynamicsCallInfo cres;
	TForeignAgentStatusInfo foreign_agent_info;

	// init the return value
	memset( &rv, 0, sizeof(rv) );
	rv.iCallResult.iServiceResult = ERR_NONE;
	
	// check that the agent is running
	rv.iCallResult = is_agent_running();
	if( rv.iCallResult.iServiceResult != ERR_NONE ) {
		return rv;
	}

	// make the call to dynamics
	cres = iDynamicsCommand.ForeignAgentGetStatus( &foreign_agent_info );
	if( cres.iResult != DC_SUCCESS ) {
		set_dynamics_error( &(rv.iCallResult), &cres );
		return rv;
	}

	// set the result
	rv.iAdvertisementsSent = foreign_agent_info.iAdvertisementsSent;
	rv.iDiscardedMalformed = foreign_agent_info.iDiscardedMalformed;
	rv.iDiscardedUnknownExtension = foreign_agent_info.iDiscardedUnknownExtension;
	rv.iDiscardedVendor = foreign_agent_info.iDiscardedVendor;
	rv.iPendingRegistrationRequests = foreign_agent_info.iPendingRegistrationRequests;
	rv.iReplysAccepted = foreign_agent_info.iReplysAccepted;
	rv.iReplysRejected = foreign_agent_info.iReplysRejected;
	rv.iRequestsAccepted = foreign_agent_info.iRequestsAccepted;
	rv.iRequestsRejected = foreign_agent_info.iRequestsRejected;
	rv.iTunnelCount = foreign_agent_info.iTunnelCount;
	return rv;
}


/****************************************************************************************
 * 
 * PUBLIC FUNCTION: destroytunnelid
 * 
 ***************************************************************************************/
TResult CSFacontroller::destroytunnelid( TFaTunnelID aArgs )
{
	TResult rv;
	TDynamicsCallInfo cres;

	// init the return value
	memset( &rv, 0, sizeof(rv) );
	rv.iServiceResult = ERR_NONE;
	
	// check that the agent is running
	rv = is_agent_running();
	if( rv.iServiceResult != ERR_NONE ) {
		return rv;
	}

	// make the call to dynamics
	cres = iDynamicsCommand.ForeignAgentDestroyTunnel( aArgs.iMobileNodeAddress );
	if( cres.iResult != DC_SUCCESS ) {
		set_dynamics_error( &rv, &cres );
		return rv;
	}

	// done 
	return rv;
}


/****************************************************************************************
 * 
 * PUBLIC FUNCTION: listtunnels
 * 
 ***************************************************************************************/
TFaTunnelList CSFacontroller::listtunnels( int aArgs )
{
	TResult res;
	TFaTunnelList rv = { 0, NULL };
	TDynamicsCallInfo cres;
	TTunnelID tunnel_list[MAXTUNNELS];
	int tunnel_count = MAXTUNNELS, i;

	// check that the agent is running
	res = is_agent_running();
	if( res.iServiceResult != ERR_NONE ) {
		return rv;
	}

	// make the call to dynamics
	cres = iDynamicsCommand.ForeignAgentGetTunnels( &tunnel_count, tunnel_list );
	if( cres.iResult != DC_SUCCESS ) {
		return rv;
	}

	// allocate memory for the list
	rv.TFaTunnelList_len = tunnel_count;
	rv.TFaTunnelList_val = (TFaTunnelID*)calloc( tunnel_count, sizeof(TFaTunnelID) );
	assert( rv.TFaTunnelList_val != NULL );

	// now return the information
	for( i = 0; i < tunnel_count; i++ ) {
		(rv.TFaTunnelList_val)[i].iAgentID = 0;
		(rv.TFaTunnelList_val)[i].iID = (tunnel_list[i]).iTunnelID;
		(rv.TFaTunnelList_val)[i].iHomeAgentAddress = (tunnel_list[i]).iHomeAgentAddress;
		(rv.TFaTunnelList_val)[i].iMobileNodeAddress = (tunnel_list[i]).iMobileNodeAddress;
	}

	// done - success
	return rv;
}

/****************************************************************************************
 * 
 * PUBLIC FUNCTION: gettunnelinfo
 * 
 ***************************************************************************************/
TFaTunnelInfo CSFacontroller::gettunnelinfo( TGetTunnelRequest aArgs )
{
	TFaTunnelInfo rv;
	TDynamicsCallInfo cres;
	TForeignAgentTunnelInfo fati;

	// init the result
	memset( &rv, 0, sizeof(rv) );
	rv.iCallResult.iServiceResult = ERR_NONE;

	// check that the agent is running
	rv.iCallResult = is_agent_running();
	if( rv.iCallResult.iServiceResult != ERR_NONE ) {
		return rv;
	}

	// make the call to dynamics
	cres = iDynamicsCommand.ForeignAgentGetTunnelInfo( aArgs.iMobileNodeAddress, &fati );
	if( cres.iResult != DC_SUCCESS ) {
		set_dynamics_error( &(rv.iCallResult), &cres );
		return rv;
	}

	// set the info
	rv.iCareofAddress = fati.iCareofAddress;
	rv.iCreationTime = fati.iCreationTime;
	rv.iExpirationTime = fati.iExpirationTime;
	rv.iHomeAgentAddress = fati.iHomeAgentAddress;
	rv.iLastTimestamp = fati.iLastTimestamp;
	rv.iMobileNodeAddress = fati.iMobileNodeAddress;
	rv.iPrivateHomeAgentID = fati.iPrivateHomeAgentID;
	rv.iRefreshTime = fati.iRefreshTime;
	rv.iSPI = fati.iSPI;
	rv.iTimeout = fati.iTimeout;
	return rv;
}



/****************************************************************************************
 * 
 * PUBLIC FUNCTION: settimeout
 * 
 ***************************************************************************************/
void CSFacontroller::settimeout( TTimeoutRequest aArgs )
{
	iDynamicsCallTimeout = aArgs.iTimeout;
	iDynamicsCommand.SetTimeout( aArgs.iTimeout );
}


/****************************************************************************************
 * 
 * PRIVATE FUNCTION: is_agent_running
 * 
 ***************************************************************************************/
TResult CSFacontroller::is_agent_running()
{	
	TResult rv;
	TCAProcessError perr;
	TProcessStatus pstatus;

	// clear the rv
	memset( &rv, 0, sizeof(rv) );

	// check that the agent was running
	if( iAgentProcess == NULL ) {
		rv.iServiceResult = ERR_INVALIDSTATE;
		return rv;
	}

	// check that the agent is still runnning
	perr = iAgentProcess->GetProcessStatus( &pstatus );
	assert( perr == CAE_NONE );
	if( pstatus != PS_STARTED ) {
		rv.iServiceResult = ERR_INVALIDSTATE;
		return rv;
	}

	// done - success
	return rv;
}


/****************************************************************************************
 * 
 * PRIVATE FUNCTION: is_agent_running
 * 
 ***************************************************************************************/
void CSFacontroller::set_dynamics_error( TResult *result, TDynamicsCallInfo *cres )
{
	result->iServiceResult = ERR_DYNAMICS_CALL_FAILED;
	result->iSubComponentResult = cres->iResult;
	result->iData0 = cres->iErrorCode;
	result->iData1 = cres->iErrorDetail;
}

