/* ====================================================================
* The Vovida Software License, Version 1.0
*
* Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The names "VOCAL", "Vovida Open Communication Application Library",
* and "Vovida Open Communication Application Library (VOCAL)" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact vocal@vovida.org.
*
* 4. Products derived from this software may not be called "VOCAL", nor
* may "VOCAL" appear in their name, without prior written
* permission of Vovida Networks, Inc.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
* NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
* IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* ====================================================================
*
* This software consists of voluntary contributions made by Vovida
* Networks, Inc. and many individuals on behalf of Vovida Networks,
* Inc. For more information on Vovida Networks, Inc., please see
* <http://www.vovida.org/>.
*
*/
static const char* const ServerContainer_cxx_Version =
"$Id: ServerContainer.cxx,v 1.39 2002/11/29 20:41:03 sprajpat Exp $";
#include "ProvisionInterface.hxx"
#include "ServerContainer.hxx"
#include "HeartbeatUtil.h"
#include "ReadLockHelper.hxx"
#include "WriteLockHelper.hxx"
#include "VIoException.hxx"
#include "HeartbeatCommon.h"
#include "NetworkConfig.hxx"
static const string RSfilename("ListOfRedirectServers");
static const string POSfilename("ListOfPdpServers");
static const string GlobConfigfilename("GlobalConfigData");
Sptr < ServerContainer > ServerContainer::theSrvContainer = 0;
/**
* Return the one Server container or create it if it doesn't already exist.
* @return Reference to the singleton
*/
ServerContainer&
ServerContainer::instance()
{
if ( theSrvContainer == 0 )
{
theSrvContainer = new ServerContainer;
}
return *theSrvContainer;
}
/**
* Constructor
*/
ServerContainer::ServerContainer()
: BaseServerContainer()
{
// get config data from PS
configRedirectServers();
configPolicyServers();
// register interest in the following files
try
{
ProvisionInterface& pif = ProvisionInterface::instance();
pif.registerForUpdate( updateRedirectServers, RSfilename,
ProvisionInterface::VCONFIG);
pif.registerForUpdate( updatePolicyServers, POSfilename,
ProvisionInterface::VCONFIG);
pif.registerForUpdate( updateServerHeartbeatParms, GlobConfigfilename,
ProvisionInterface::VCONFIG);
}
catch (VException& e)
{
cpLog(LOG_ALERT, "Failed to connect to Provisioning Server, reason %s",
e.getDescription().c_str());
}
displayLists();
}
/**
* Copy Constructor
* @param rhs Object from which to copy
*/
ServerContainer::ServerContainer( const ServerContainer& rhs )
{
if (this != &rhs)
copyRhsToThis( rhs );
}
/**
* Operator overload for "="
* @param rhs Object from which to copy
* @return Reference to this object with new data
*/
ServerContainer&
ServerContainer::operator=( const ServerContainer& rhs )
{
if ( this != &rhs )
{
BaseServerContainer::operator= (rhs);
copyRhsToThis( rhs );
}
return *this;
}
/**
* Copy member data from given object into this one
* @param rhs Object from which to copy
*/
void
ServerContainer::copyRhsToThis( const ServerContainer& rhs )
{
itsRSList = rhs.itsRSList;
itsPOSList = rhs.itsPOSList;
}
/**
* Obtain all servers of the type specified from Provisioning.
* @param type Type of server to obtain
* @param retList Compiled list of servers to pass back
*/
void
ServerContainer::getServersFromPS( const ServerType type, vector < Data > & retList)
{
list < string > tmpList;
switch (type)
{
case SERVER_RS:
{
try
{
ProvisionInterface::instance().getRedirectServers( tmpList );
}
catch (VException& e)
{
cpLog(LOG_ALERT, "Failed to connect to Provisioning Server, reason %s",
e.getDescription().c_str());
}
}
break;
case SERVER_POS:
{
try
{
ProvisionInterface::instance().getPolicyServers( tmpList );
}
catch (VException& e)
{
cpLog(LOG_ALERT, "Failed to connect to Provisioning Server, reason %s",
e.getDescription().c_str());
}
}
break;
default:
break;
}
bool duplicateEntryFound;
/// add server to vector
for (list < string > ::iterator i = tmpList.begin(); i != tmpList.end(); ++i)
{
/// check for duplicate entries in list
duplicateEntryFound = false;
LocalScopeAllocator lo;
for (vector < Data > ::iterator j = retList.begin(); j != retList.end(); ++j)
{
string serverInList = string(j->getData(lo) );
if ( *i == serverInList )
{
duplicateEntryFound = true;
break;
}
}
if (duplicateEntryFound)
{
cpLog( LOG_ALERT, "*** Duplicate Entry Found In LIST: %s ***", i->c_str() );
cpLog( LOG_ALERT, "*** DO NOT add to Container ***");
}
else
{
Data addressPort(*i);
if(NetworkConfig::instance().isDualStack())
{
NetworkAddress na(*i);
char buf[256];
sprintf(buf, "%s:%d", na.getHostName().c_str(), na.getPort());
addressPort = buf;
}
cpLog( LOG_DEBUG, "server:port=%s", addressPort.logData());
retList.push_back( addressPort );
}
}
}
/**
* Scan the given list for duplicate servers and remove them.
* @param list List of servers
*/
void
ServerContainer::removeDuplicatesFromList( Sptr < vector < Data > > & list )
{
ReadLockHelper tableHelper(tableLock);
bool done = false, duplicateEntryFound = false;
while (!done)
{
TableIter iter;
duplicateEntryFound = false;
for (vector < Data > ::iterator i = list->begin();
i != list->end(); ++i)
{
iter = serverList.find(*i);
if (iter != serverList.end())
{
cpLog( LOG_ALERT, "*** Duplicate Entry Found in CONTAINER: %s ***", i->logData() );
cpLog( LOG_ALERT, "*** DO NOT add to Container ***");
duplicateEntryFound = true;
list->erase(i);
break;
}
}
if (!duplicateEntryFound)
{
done = true;
}
}
}
/**
* Compile a list of all Redirect Servers configured in the system.
*/
void
ServerContainer::configRedirectServers()
{
WriteLockHelper rsHelper(rsLock);
/// get RSlist
itsRSList = new vector < Data > ;
getServersFromPS( SERVER_RS, *itsRSList );
removeDuplicatesFromList(itsRSList);
/// create Redirect Servers
for (vector < Data > ::iterator i = itsRSList->begin();
i != itsRSList->end(); ++i)
{
//Since address are in Ipv4 address, may cause problem in lookup
//when running on ipv4+ipv6, so store as host name
Data smartServer(*i);
if(NetworkConfig::instance().isDualStack())
{
NetworkAddress na(*i);
char buf[256];
sprintf(buf, "%s:%d", na.getHostName().c_str(), na.getPort());
smartServer = buf;
}
cpLog( LOG_DEBUG, "Adding RS from PS: %s", smartServer.logData());
addServer( smartServer, SERVER_RS );
/// display updated data
display( smartServer );
}
}
/**
* Compile a list of all Policy Servers configured in the system.
*/
void
ServerContainer::configPolicyServers()
{
WriteLockHelper posHelper(posLock);
/// get POSlist
itsPOSList = new vector < Data > ;
getServersFromPS( SERVER_POS, *itsPOSList );
removeDuplicatesFromList(itsPOSList);
/// create Policy Servers
for (vector < Data > ::iterator i = itsPOSList->begin();
i != itsPOSList->end(); ++i)
{
cpLog( LOG_DEBUG, "from PS new POS: %s", i->logData() );
/// get server id
Data smartServer(*i);
addServer( smartServer, SERVER_POS );
/// display updated data
display( smartServer );
}
}
/**
* Destructor
*/
ServerContainer::~ServerContainer( )
{}
/**
* Obtain a list of servers for the specified type
* @param type Type of server to obtain a list of
* @return List of requested servers
*/
const Sptr < vector < Data > >
ServerContainer::getListofServersRef( const ServerType type ) const
{
switch (type)
{
case SERVER_RS:
{
return itsRSList;
}
case SERVER_POS:
{
return itsPOSList;
}
default:
{
cpLog(LOG_ERR, "Unknown server type");
return 0;
}
}
}
/**
* Obtain a list of active servers of the type specified
* @param type Server type
* @param listofActiveServers List of active servers obtained
*/
void
ServerContainer::getListofActive( const ServerType type, Sptr < vector < Data > > & listofActiveServers )
{
cpLog( LOG_DEBUG_HB, "ServerContainer::getListofActive %s",
convertToString(type) );
switch (type)
{
case SERVER_RS:
{
ReadLockHelper rsHelper(rsLock);
for (vector < Data > ::iterator i = itsRSList->begin();
i != itsRSList->end(); ++i)
{
Data server(*i);
if (getStatus(server) == Active)
listofActiveServers->push_back(*i);
}
}
break;
case SERVER_POS:
{
ReadLockHelper posHelper(posLock);
for (vector < Data > ::iterator i = itsPOSList->begin();
i != itsPOSList->end(); ++i)
{
Data server(*i);
if (getStatus(server) == Active)
listofActiveServers->push_back(*i);
}
}
break;
default:
break;
}
}
/**
* Deal with a heartbeat event from the given server
* @param key Server who sent the heartbeat
* @return True if server is recognized, false if not
*/
bool
ServerContainer::processHeartbeat( const Data& key)
{
Sptr < Server > serverPtr;
if (search( key, serverPtr) )
{
ReadLockHelper tableHelper(tableLock);
/// print data contained in the server object
switch (serverPtr->getType() )
{
case SERVER_RS:
case SERVER_POS:
serverPtr->processHeartbeat(key);
break;
default:
break;
};
displayServer(*serverPtr);
return true;
}
else
{
//cpLog (LOG_ALERT, "Failed search for key: %s", key.logData());
return false;
}
}
/**
* Check all servers to see if they are still actively heartbeating
*/
void
ServerContainer::doHouseKeeping()
{
Sptr < Server > serverPtr;
cpLog( LOG_DEBUG_HB, "");
cpLog( LOG_DEBUG_HB, "****** do HouseKeeping *****");
ReadLockHelper tableHelper(tableLock);
if ( !serverList.empty() )
{
for ( TableIter i = serverList.begin(); i != serverList.end(); ++i)
{
serverPtr = i->second;
if ( serverPtr->getStatus() != Inactive )
{
cpLog( LOG_DEBUG_HB, "%s", i->first.logData() );
}
switch (serverPtr->getType() )
{
case SERVER_RS:
case SERVER_POS:
serverPtr->doHouseKeeping(i->first);
break;
default:
break;
}
}
}
else
{
cpLog( LOG_DEBUG_HB, "nothing in server container");
}
cpLog( LOG_DEBUG_HB, "****** finished HouseKeeping *****");
cpLog( LOG_DEBUG_HB, "");
}
/**
* A change was made to the RS's in the provisioning server.
* Delete the stored RS server list and recreate it with the new data.
*/
void
ServerContainer::updateRSsFromPS()
{
{ // create a scope for the lock helper object
WriteLockHelper rsHelper(rsLock);
/// delete all RSs in Server Container
for (vector < Data > ::iterator i = itsRSList->begin(); i < itsRSList->end(); ++i)
{
cpLog( LOG_DEBUG, "delete RS: %s", i->logData() );
Data server(*i);
/// delete from Server Container
remove(server);
}
/// clear RSList
itsRSList->clear();
}
/// reconfigure RSs from scratch
configRedirectServers();
displayLists();
}
/**
* A change was made to the Policy servers in the provisioning server.
* Delete the stored server list and recreate it with the new data.
*/
void
ServerContainer::updatePOSsFromPS()
{
{ // create a scope for the lock helper object
WriteLockHelper posHelper(posLock);
/// delete all POSs in Server Container
for (vector < Data > ::iterator i = itsPOSList->begin(); i < itsPOSList->end(); ++i)
{
cpLog( LOG_DEBUG, "delete POS: %s", i->logData() );
Data server(*i);
/// delete from Server Container
remove(server);
}
/// clear POSList
itsPOSList->clear();
}
/// reconfigure POSs from scratch
configPolicyServers();
displayLists();
}
/**
* The heartbeat parameters were altered in Provisioning.
* Update the Max Missed Heartbeat value.
*/
void
ServerContainer::updateHBParmsFromPS()
{
cpLog( LOG_DEBUG, "updating Heartbeat Parms in ServerContainer");
WriteLockHelper tableHelper(tableLock);
/// get pointer to global config object
VGlobalConfigData globalConfigData;
try
{
ProvisionInterface::instance().getConfigData(globalConfigData);
}
catch (VIoException& e)
{
cpLog(LOG_ALERT, "Failed to get data from Provisioning Server, reason %s",
e.getDescription().c_str());
}
catch (VException& e)
{
cpLog(LOG_ALERT, "Failed to connect to Provisioning Server, reason %s",
e.getDescription().c_str());
}
int newValue = globalConfigData.getMaxMissedHB();
int oldValue = serverList.begin()->second->getMaxMissedHB();
cpLog( LOG_DEBUG, "maxMissedHB old: %d new: %d", oldValue, newValue );
if (( !serverList.empty() ) && ( oldValue != newValue ))
{
for ( TableIter i = serverList.begin(); i != serverList.end(); ++i)
{
i->second->setMaxMissedHB( newValue );
}
}
}
/**
* Display all lists
*/
void
ServerContainer::displayLists()
{
ReadLockHelper rsHelper(rsLock);
ReadLockHelper posHelper(posLock);
cpLog( LOG_DEBUG, "----------- Redirect Servers --------");
for (vector < Data > ::iterator i = itsRSList->begin();
i < itsRSList->end(); ++i)
{
cpLog( LOG_DEBUG, "RS: %s", i->logData() );
}
cpLog( LOG_DEBUG, "----------- Policy Servers --------");
for (vector < Data > ::iterator i = itsPOSList->begin();
i < itsPOSList->end(); ++i)
{
cpLog( LOG_DEBUG, "POS: %s", i->logData() );
}
}
/**
* The Provisioning Server is notifying us of a change in RS's.
* @param data Contents of file changed
* @param filename Name of file altered
* @param bool Delete flag
*/
void
updateRedirectServers(const string& data, const string& fileName, bool)
{
/// update RS list
ServerContainer::instance().updateRSsFromPS();
}
/**
* The Provisioning Server is notifying us of a change in POS's.
* @param data Contents of file changed
* @param filename Name of file altered
* @param bool Delete flag
*/
void
updatePolicyServers(const string& data, const string& fileName, bool)
{
/// update POS list
ServerContainer::instance().updatePOSsFromPS();
}
/**
* The Provisioning Server is notifying us of a change in Heartbeat Parms.
* @param data Contents of file changed
* @param filename Name of file altered
* @param bool Delete flag
*/
void
updateServerHeartbeatParms(const string& data, const string& fileName, bool)
{
/// update Heartbeat Parms
ServerContainer::instance().updateHBParmsFromPS();
}
/// End of File
syntax highlighted by Code2HTML, v. 0.9.1