/* ====================================================================
* 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 RoundRobinServers_cxx_Version =
"$Id: RoundRobinServers.cxx,v 1.21 2002/11/12 20:25:43 veer Exp $";
#include "RoundRobinServers.hxx"
#include "HeartbeatCommon.h"
#include "ProvisionInterface.hxx"
#include "VRedirectServerData.hxx"
#include "ServerContainer.hxx"
// static data declarations
RoundRobinServers* RoundRobinServers::_theRoundRobinServers = 0;
RoundRobinServers::RoundRobinServers()
{}
RoundRobinServers::~RoundRobinServers()
{}
/**
* Obtain the singleton occurrence of this object
* @param serverType Type of server
* @return Pointer to the singleton
*/
RoundRobinServers&
RoundRobinServers::instance( const ServerType serverType )
{
if ( _theRoundRobinServers == 0)
{
_theRoundRobinServers = new RoundRobinServers;
}
_theRoundRobinServers->updateServerContainer( serverType );
return *_theRoundRobinServers;
}
/**
* Store the server type and obtain the list of servers for that type
* @param serverType Type of server
*/
void RoundRobinServers::updateServerContainer( const ServerType serverType )
{
_serverType = serverType;
_listOfServers = ServerContainer::instance().getListofServersRef( serverType );
}
/**
* Copy Constructor
* @param rhs Object from which to copy
*/
RoundRobinServers::RoundRobinServers( const RoundRobinServers& rhs )
{
if ( this != &rhs )
{
copyRhsToThis( rhs );
}
}
/**
* Copy member data from given object into this one
* @param rhs Object from which to copy
* @return Reference to this object with new data
*/
RoundRobinServers&
RoundRobinServers::operator=(const RoundRobinServers& rhs)
{
if ( this != &rhs )
{
copyRhsToThis( rhs );
}
return *this;
}
/**
* Copy member data from given object into this one
* @param rhs Object from which to copy
*/
void
RoundRobinServers::copyRhsToThis( const RoundRobinServers& rhs )
{
_pServer = rhs._pServer;
_pServerPort = rhs._pServerPort;
_listOfServers = rhs._listOfServers;
_serverType = rhs._serverType;
}
/**
* Display the list of servers stored in this object.
*/
void
RoundRobinServers::displayServerList() const
{
switch ( _serverType )
{
case SERVER_RS:
cpLog (LOG_DEBUG, "Redirect server info:\n");
case SERVER_POS:
cpLog (LOG_DEBUG, "Policy server info:\n");
default:
cpLog (LOG_DEBUG, "Unknown server type info:\n");
}
for ( vector < Data > ::const_iterator itr = _listOfServers->begin();
itr != _listOfServers->end(); itr++ )
{
cpLog (LOG_DEBUG, " %s", itr->logData());
}
}
/**
* Obtain a server using a hash function and strip off the port before returning.
* @param hash_value Value with which to hash the list of servers
* @return Host address of chosen server
*/
const Data
RoundRobinServers::getHost( const Data& hash_value )
{
/// seperate address and port (actually only need address)
string newAddress, addr_port = hashIntoServer( hash_value );
cpLog(LOG_DEBUG, "Hash %s into server: %s", hash_value.logData(), addr_port.c_str());
string::size_type colonPos = addr_port.find(":");
if (colonPos != string::npos)
{
newAddress = addr_port.substr(0, colonPos);
}
else
{
newAddress = addr_port;
}
return newAddress;
}
/**
* Obtain a server port by hashing into the server list and stripping
* off the host before returning.
* @param hash_value Value with which to hash the list of servers
* @return Port of chosen server
*/
int
RoundRobinServers::getPort( const Data& hash_value )
{
/// seperate address and port (actually only need port)
string newPort, addr_port = hashIntoServer( hash_value );
string::size_type colonPos = addr_port.find(":");
if (colonPos != string::npos)
{
newPort = addr_port.substr(colonPos + 1);
}
else
{
newPort = "";
}
return atoi(newPort.c_str());
}
void
RoundRobinServers::getHostNPort( const Data& hash_value , Data& host, int& port)
{
/// seperate address and port (actually only need port)
string newPort, addr_port = hashIntoServer( hash_value );
cpLog(LOG_DEBUG, "Hash %s into server: %s", hash_value.logData(), addr_port.c_str());
string::size_type colonPos = addr_port.find(":");
if (colonPos != string::npos)
{
host = addr_port.substr(0, colonPos);
newPort = addr_port.substr(colonPos + 1);
}
else
{
host = addr_port;
newPort = "";
}
port = atoi(newPort.c_str());
}
/**
* Determine if the given host and port match a valid server
* @param host Host portion of address to be verified
* @param port Port portion of address to be verified
* @return True if server exists, false if not
*/
bool
RoundRobinServers::isExistingServer( const Data& host, const int port ) const
{
Sptr < Data > searchString = new Data (host);
*searchString += ":";
*searchString += Data(port);
return isExistingServer( searchString );
}
/**
* Determine if given server matches an existing server in the list
* @param searchString Server address
* @return True if server exists, false if not
*/
bool
RoundRobinServers::isExistingServer( Sptr < Data > searchString ) const
{
unsigned int numOfServers = _listOfServers->size();
for ( unsigned int i = 0; i < numOfServers; i++ )
{
if ( (*_listOfServers)[i] == *searchString )
{
return true;
}
}
cpLog(LOG_ERR, "non exisiting server %s", searchString->logData());
return false;
}
/**
* Obtain a number using a hashing algorithm
* @param hash_key Key to be used in the hash
* @return Integer result of the hash
*/
unsigned
RoundRobinServers::hashingFunction( const Data& hash_key ) const
{
unsigned int result = 0;
LocalScopeAllocator lo;
const char* p = hash_key.getData(lo);
int len = hash_key.length();
/// using bytes of key's representation
assert (len);
assert (p);
while ( len-- )
{
result = (result << 1) ^ *p++;
}
return result;
}
/**
* Obtain a server from the list using a hash function
* @param hash_key Key to be used in the hash
* @return Server resulting from the hash
*/
string
RoundRobinServers::hashIntoServer( const Data& hash_key )
{
LocalScopeAllocator lo;
string result;
unsigned int hashValue = hashingFunction( hash_key );
if ( _listOfServers->size() == 0 )
{
cpLog(LOG_ERR, "No known servers");
assert(0);
}
int modHashValue = hashValue % _listOfServers->size();
/// comfirm server is up
Data testServer((*_listOfServers)[modHashValue]);
if ( ServerContainer::instance().getStatus( testServer ) != Active )
{
cpLog(LOG_DEBUG, "%s is down. Rehashing to active server", testServer.logData());
Sptr < vector < Data > > listOfActiveServers = new vector < Data > ;
ServerContainer::instance().getListofActive( _serverType, listOfActiveServers );
if ( listOfActiveServers->size() == 0 )
{
cpLog(LOG_ERR, "No known active servers, default to first server");
result = (*_listOfServers)[0].getData(lo);
}
else
{
modHashValue = hashValue % listOfActiveServers->size();
result = (*listOfActiveServers)[modHashValue].getData(lo);
}
}
else
result = testServer.getData(lo);
return result;
}
syntax highlighted by Code2HTML, v. 0.9.1