1114 lines
31 KiB
C++
1114 lines
31 KiB
C++
//----------------------------------------------------------------------------
|
|
//
|
|
// Copyright (C) Intel Corporation, 2007 - 2008.
|
|
//
|
|
// File: Options.cpp
|
|
//
|
|
// Contents: Parses a static and dynamic configuration file.
|
|
// Provides access to its elements, with the actual type
|
|
// of the element obtained from the configuration file.
|
|
//
|
|
// Notes:
|
|
//----------------------------------------------------------------------------
|
|
|
|
//------------------
|
|
// Includes
|
|
//------------------
|
|
#include "Options.h"
|
|
|
|
#include <ace/OS_NS_sys_stat.h>
|
|
|
|
#include "TypeValidationsExtraction.h"
|
|
#include "DataStructures.h"
|
|
#include "CFParser.h"
|
|
#include "ListParser.h"
|
|
|
|
#include <memory>
|
|
|
|
using namespace std;
|
|
|
|
//------------------
|
|
// Defines
|
|
//------------------
|
|
#define FILES "FILES"
|
|
#define PORT "PORT"
|
|
#define IP "IP"
|
|
#define INET "INET"
|
|
|
|
#define ZERO_TIME 0
|
|
|
|
//------------------
|
|
// Statics init
|
|
//------------------
|
|
Options * Options::_instance = NULL;
|
|
bool Options::_init = false;
|
|
ACE_Mutex Options::_ctor_mutex;
|
|
|
|
//----------------------------------------
|
|
// Options public functions implementation
|
|
//----------------------------------------
|
|
|
|
/*
|
|
* Creates the Options Singleton.
|
|
* Requires the filenames to parse, and the type of formats that are
|
|
* allowed and needed.
|
|
* staticFileName - Pointer to the name of the static file to parse.
|
|
* dynamicFileName - Pointer to the name of the dynamic file to parse.
|
|
* format_static_mandatory - Pointer to the static mandatory format.
|
|
* format_static_optional - Pointer to the static optional format.
|
|
* format_dynamic_mandatory - Pointer to the dynamic mandatory format.
|
|
* format_dynamic_optional - Pointer to the dynamic optional format.
|
|
* Returns STATUS_FAILURE on failure.
|
|
* Returns STATUS_SUCCESS on success.
|
|
*/
|
|
STATUS Options::createInstance ( const ACE_TCHAR * staticFileName,
|
|
const ACE_TCHAR * dynamicFileName,
|
|
const Format * format_static_mandatory,
|
|
const Format * format_static_optional,
|
|
const Format * format_dynamic_mandatory,
|
|
const Format * format_dynamic_optional)
|
|
{
|
|
STATUS status = STATUS_FAILURE;
|
|
|
|
// init is set to false. if a construction is
|
|
// performed successfully than init will become true
|
|
if (Options::_instance == NULL)
|
|
{
|
|
// do not allow two constructions simultaneously
|
|
Options::_ctor_mutex.acquire();
|
|
// do not allow more than one construction at all
|
|
if (!_init)
|
|
{
|
|
Options::_instance = new Options(staticFileName,
|
|
dynamicFileName,
|
|
format_static_mandatory,
|
|
format_static_optional,
|
|
format_dynamic_mandatory,
|
|
format_dynamic_optional);
|
|
}
|
|
Options::_ctor_mutex.release();
|
|
|
|
if (!_init)
|
|
{
|
|
ACE_ERROR ((MY_ERROR ACE_TEXT ("Creating Options instance failed.\n")));
|
|
delete Options::_instance;
|
|
Options::_instance = NULL;
|
|
return status;
|
|
}
|
|
}
|
|
|
|
status = STATUS_SUCCESS;
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
* Return pointer to singleton of Options.
|
|
* Must be called only after createInstance was called.
|
|
* Returns NULL if no such object exist.
|
|
*/
|
|
Options * Options::instance (void)
|
|
{
|
|
return Options::_instance;
|
|
}
|
|
|
|
/*
|
|
* Default destructor.
|
|
* If error occurs at any point that can not be recovered than
|
|
* destruction is stopped and not all elements are deleted
|
|
*/
|
|
Options::~Options (void)
|
|
{
|
|
ACE_TString sectionName, elementName;
|
|
|
|
auto_ptr<ElementHash::constOuterIter> hashOuterP_begin(_element_hash.beginOuters());
|
|
auto_ptr<ElementHash::constOuterIter> hashOuterP_end(_element_hash.endOuters());
|
|
|
|
if ((hashOuterP_begin.get() == NULL) || (hashOuterP_end.get() == NULL))
|
|
{
|
|
return;
|
|
}
|
|
ElementHash::constOuterIter hashOuterIter = * hashOuterP_begin;
|
|
|
|
for (; hashOuterIter != *hashOuterP_end; hashOuterIter++)
|
|
{
|
|
auto_ptr<ElementHash::constInnerIter> hashInnerIterP_begin
|
|
(_element_hash.beginInners(hashOuterIter->first));
|
|
auto_ptr<ElementHash::constInnerIter> hashInnerIterP_end
|
|
(_element_hash.endInners(hashOuterIter->first));
|
|
|
|
sectionName = hashOuterIter->first;
|
|
// Do not exit, it may happen that next iteration will work
|
|
if ((hashInnerIterP_begin.get() != NULL) && (hashInnerIterP_end.get() != NULL))
|
|
{
|
|
ElementHash::constInnerIter hashInnerIter = * hashInnerIterP_begin;
|
|
|
|
for (; hashInnerIter != *hashInnerIterP_end; hashInnerIter++)
|
|
{
|
|
elementName = hashInnerIter->first;
|
|
|
|
deleteElementContent(sectionName, elementName);
|
|
}
|
|
}
|
|
}
|
|
|
|
_element_hash.cleanHash();
|
|
_temp_String_Hash.cleanHash();
|
|
}
|
|
|
|
/*
|
|
* Reads the static file and parses its elements.
|
|
* After successful usage, the static elements may be received.
|
|
* Returns STATUS_FAILURE on failure.
|
|
* Returns STATUS_SUCCESS on success.
|
|
*/
|
|
STATUS Options::read_static_file(void)
|
|
{
|
|
STATUS status = STATUS_FAILURE;
|
|
|
|
// Sanity check
|
|
if (_static_config_file == NULL ||
|
|
_format_static_mandatory == NULL ||
|
|
_format_static_optional == NULL)
|
|
{
|
|
return status;
|
|
}
|
|
if (read_file(_static_config_file, _format_static_mandatory, _format_static_optional))
|
|
{
|
|
return status;
|
|
}
|
|
|
|
if (read_all_external_files() == STATUS_FAILURE)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
status = STATUS_SUCCESS;
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
* Reads the dynamic files and parses its elements.
|
|
* After successful usage, the dynamic elements may be received.
|
|
* Returns -1 on failure.
|
|
* Returns 0 if none of the files were changed, and therefore not read.
|
|
* Returns 1 on read of only the dynamic config file.
|
|
* Returns 2 on read of the dynamic config file and at least one of the external files.
|
|
* Returns 3 on read of at least one of the external files. (no read of the dynamic config file).
|
|
*/
|
|
int Options::read_dynamic_file(void)
|
|
{
|
|
int ret = 0;
|
|
bool readConfigFile = false;
|
|
bool readExternalFiles = false;
|
|
|
|
// Sanity check
|
|
if (_dynamic_config_file == NULL ||
|
|
_format_dynamic_mandatory == NULL ||
|
|
_format_dynamic_optional == NULL)
|
|
{
|
|
return STATUS_FAILURE;
|
|
}
|
|
|
|
ACE_stat fileStats;
|
|
ACE_OS::stat(_dynamic_config_file, &fileStats);
|
|
if (_lastModification != fileStats.st_mtime)
|
|
{
|
|
if (read_file(_dynamic_config_file, _format_dynamic_mandatory, _format_dynamic_optional) != STATUS_SUCCESS)
|
|
{
|
|
return STATUS_FAILURE;
|
|
}
|
|
_lastModification = fileStats.st_mtime;
|
|
readConfigFile = true;
|
|
}
|
|
|
|
int externalFilesRead = read_all_external_files();
|
|
if (externalFilesRead == STATUS_FAILURE)
|
|
{
|
|
return STATUS_FAILURE;
|
|
}
|
|
|
|
if (externalFilesRead > 0)
|
|
{
|
|
readExternalFiles = true;
|
|
}
|
|
|
|
if (readConfigFile)
|
|
{
|
|
if (readExternalFiles)
|
|
{
|
|
ret = 2;
|
|
}
|
|
else
|
|
{
|
|
ret = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (readExternalFiles)
|
|
{
|
|
ret = 3;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
//----------------------------------------
|
|
// Options private functions implementation
|
|
//----------------------------------------
|
|
|
|
/*
|
|
* Constructor.
|
|
* Requires the filenames to parse, and the type of formats that are
|
|
* allowed and needed.
|
|
* staticFileName - Pointer to the name of the static file to parse.
|
|
* dynamicFileName - Pointer to the name of the dynamic file to parse.
|
|
* format_static_mandatory - Pointer to the static mandatory format.
|
|
* format_static_optional - Pointer to the static optional format.
|
|
* format_dynamic_mandatory - Pointer to the dynamic mandatory format.
|
|
* format_dynamic_optional - Pointer to the dynamic optional format.
|
|
*/
|
|
Options::Options(const ACE_TCHAR * staticFileName,
|
|
const ACE_TCHAR * dynamicFileName,
|
|
const Format * format_static_mandatory,
|
|
const Format * format_static_optional,
|
|
const Format * format_dynamic_mandatory,
|
|
const Format * format_dynamic_optional) : _lastModification(ZERO_TIME),
|
|
_format_static_mandatory(), _format_static_optional(), _format_dynamic_mandatory(),
|
|
_format_dynamic_optional()
|
|
{
|
|
if ( (staticFileName == NULL) ||
|
|
(dynamicFileName == NULL) )
|
|
{
|
|
return;
|
|
}
|
|
if ( (format_static_mandatory == NULL) ||
|
|
(format_static_optional == NULL) ||
|
|
(format_dynamic_mandatory == NULL) ||
|
|
(format_dynamic_optional == NULL) )
|
|
{
|
|
return;
|
|
}
|
|
if ((ACE_OS::strlen(staticFileName) <= MAXPATHLEN + 1) ||
|
|
(ACE_OS::strlen(dynamicFileName) <= MAXPATHLEN + 1))
|
|
{
|
|
ACE_OS::strcpy (this->_static_config_file, staticFileName);
|
|
ACE_OS::strcpy (this->_dynamic_config_file, dynamicFileName);
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
|
|
_format_static_mandatory = format_static_mandatory;
|
|
_format_static_optional = format_static_optional;
|
|
_format_dynamic_mandatory = format_dynamic_mandatory;
|
|
_format_dynamic_optional = format_dynamic_optional;
|
|
_init = true;
|
|
}
|
|
|
|
/*
|
|
* Reads the file and parses its elements according to the formats given.
|
|
* This is the main bulk function, after which the static file is parsed.
|
|
* fileName - filename to be read
|
|
* format_mandatory - mandatory format to use
|
|
* format_optional - optional format to use
|
|
* Returns STATUS_FAILURE on failure.
|
|
* Returns STATUS_SUCCESS on success.
|
|
*/
|
|
STATUS Options::read_file(const ACE_TCHAR * fileName, const Format * format_mandatory, const Format * format_optional)
|
|
{
|
|
STATUS status = STATUS_FAILURE;
|
|
|
|
ACE_GUARD_RETURN(ACE_Recursive_Thread_Mutex,
|
|
locker1,
|
|
_mutex, STATUS_FAILURE);
|
|
// Sanity check after mutex
|
|
if (fileName == NULL ||
|
|
format_mandatory == NULL ||
|
|
format_optional == NULL)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
CF_Parser parser;
|
|
if (parser.parseToCanonicalStringHash(fileName, _temp_String_Hash) != PARSER_STATUS_SUCCESS)
|
|
{
|
|
return status;
|
|
}
|
|
if (build_element_hash(format_mandatory, format_optional) != STATUS_SUCCESS)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
// Finished building the hash.
|
|
// Now it should be checked that all the mandatory values were entered
|
|
if (checkFormat(format_mandatory, true) != STATUS_SUCCESS)
|
|
{
|
|
return status;
|
|
}
|
|
if (checkFormat(format_optional, false) != STATUS_SUCCESS)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
* Builds the element hash according to previously entered parsing data to the
|
|
* string hash.
|
|
* Builds it according to the given formats -
|
|
* If an element parsed is missing from the mandatory and optional format than an error is ensued.
|
|
* Returns STATUS_FAILURE on failure.
|
|
* Returns STATUS_SUCCESS on success.
|
|
*/
|
|
STATUS Options::build_element_hash(const Format * mandatory_format, const Format * optional_format)
|
|
{
|
|
STATUS status = STATUS_FAILURE;
|
|
|
|
if (mandatory_format == NULL ||
|
|
optional_format == NULL)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
ACE_TString sectionName, elementName, elementValue;
|
|
Element_Type_Enum * elementType = NULL;
|
|
ACE_TStringHash::constInnerIter hashInnerIter;
|
|
ACE_TStringHash::constOuterIter hashOuterIter;
|
|
|
|
auto_ptr<ACE_TStringHash::constOuterIter> hashOuterP_begin(_temp_String_Hash.beginOuters());
|
|
auto_ptr<ACE_TStringHash::constOuterIter> hashOuterP_end(_temp_String_Hash.endOuters());
|
|
|
|
if ((hashOuterP_begin.get() == NULL) || (hashOuterP_end.get() == NULL))
|
|
{
|
|
return status;
|
|
}
|
|
|
|
hashOuterIter = * hashOuterP_begin;
|
|
for (; hashOuterIter != *hashOuterP_end; hashOuterIter++) {
|
|
|
|
auto_ptr<ACE_TStringHash::constInnerIter> hashInnerIterP_begin
|
|
(_temp_String_Hash.beginInners(hashOuterIter->first));
|
|
auto_ptr<ACE_TStringHash::constInnerIter> hashInnerIterP_end
|
|
(_temp_String_Hash.endInners(hashOuterIter->first));
|
|
|
|
if ((hashInnerIterP_begin.get() == NULL) || (hashInnerIterP_end.get() == NULL))
|
|
{
|
|
return status;
|
|
}
|
|
hashInnerIter = * hashInnerIterP_begin;
|
|
|
|
for (; hashInnerIter != *hashInnerIterP_end; hashInnerIter++)
|
|
{
|
|
sectionName = hashOuterIter->first;
|
|
elementName = hashInnerIter->first;
|
|
elementValue= hashInnerIter->second;
|
|
// obtain element type
|
|
if (obtainElementType(mandatory_format, optional_format,
|
|
sectionName, elementName, &elementType) != STATUS_SUCCESS)
|
|
{
|
|
return status;
|
|
}
|
|
if (addToElementHash(sectionName, elementName,
|
|
elementType->getElementType(), elementValue) != STATUS_SUCCESS)
|
|
{
|
|
return status;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Clean up temp hash - there were no New's in it. Can simply clear hash
|
|
_temp_String_Hash.cleanHash();
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
/*
|
|
* Adds an element to the element hash, putting it in the correct section, and element in the section,
|
|
* and providing it with the correct type (using elemType). The element value is obtained from
|
|
* elementValue.
|
|
* sectionName - section to put the element in
|
|
* elementName - element name in the section to put the element in
|
|
* elemType - the type of the element according which the needed type for the element is decided.
|
|
* elementValue- the value of the element.
|
|
* Returns STATUS_FAILURE on failure.
|
|
* Returns STATUS_SUCCESS on success.
|
|
*/
|
|
STATUS Options::addToElementHash(const ACE_TString §ionName,
|
|
const ACE_TString &elementName,
|
|
const ELEMENT_TYPES_ENUM &elemType,
|
|
ACE_TString &elementValue)
|
|
{
|
|
STATUS status = STATUS_FAILURE;
|
|
|
|
//Authentication_Param authParam;
|
|
LogMasks mask;
|
|
time_t timeVal;
|
|
URL_Wrapper * mc_data = NULL;
|
|
MCList * mc_list = NULL;
|
|
ServerData * as_data = NULL;
|
|
AuthServerHash * as_hash = NULL;
|
|
|
|
// check if in FILE section
|
|
ACE_TString sectionNameUpper = toUpper(sectionName);
|
|
if (sectionNameUpper.compare(FILES) == STATUS_SUCCESS)
|
|
{
|
|
ACE_TString fullFileName;
|
|
fullFileName += absolutePath;
|
|
fullFileName += elementValue;
|
|
if (addSingleElement<ACE_TString>(sectionName, elementName, fullFileName) != STATUS_SUCCESS)
|
|
{
|
|
return status;
|
|
}
|
|
status = STATUS_SUCCESS;
|
|
return status;
|
|
}
|
|
|
|
switch(elemType) {
|
|
case BOOL_TYPE:
|
|
bool cond;
|
|
if (validateAndGetElement(elementValue, cond) != STATUS_SUCCESS)
|
|
{
|
|
ACE_ERROR ((MY_ERROR ACE_TEXT ("Invalid parameter: %s. Must be boolean.\n"),
|
|
elementValue.c_str()));
|
|
return status;
|
|
}
|
|
if (addSingleElement<bool>(sectionName, elementName, cond) != STATUS_SUCCESS)
|
|
{
|
|
return status;
|
|
}
|
|
break;
|
|
case UNSIGNED_INT_TYPE:
|
|
unsigned int num;
|
|
if (validateAndGetElement(elementValue, num) != STATUS_SUCCESS)
|
|
{
|
|
ACE_ERROR ((MY_ERROR ACE_TEXT ("Invalid parameter: %s. Must be unsigned int.\n"),
|
|
elementValue.c_str()));
|
|
return status;
|
|
}
|
|
if (addSingleElement<unsigned int>(sectionName, elementName, num) != STATUS_SUCCESS)
|
|
{
|
|
return status;
|
|
}
|
|
break;
|
|
case STRING_TYPE:
|
|
if (addSingleElement<ACE_TString>(sectionName, elementName, elementValue) != STATUS_SUCCESS)
|
|
{
|
|
return status;
|
|
}
|
|
break;
|
|
case PORT_TYPE:
|
|
unsigned short port;
|
|
if ((validateAndGetElement(elementValue, port) != STATUS_SUCCESS) ||
|
|
(validatePort(port) != STATUS_SUCCESS))
|
|
{
|
|
ACE_ERROR ((MY_ERROR ACE_TEXT ("Invalid parameter: %s. Must be unsigned short.\n"),
|
|
elementValue.c_str()));
|
|
return status;
|
|
}
|
|
if (addSingleElement<unsigned short>(sectionName, elementName, port) != STATUS_SUCCESS)
|
|
{
|
|
return status;
|
|
}
|
|
// try to add INET if possible
|
|
/*if (addINET(sectionName, elementName, true) != STATUS_SUCCESS)
|
|
{
|
|
return status;
|
|
}*/
|
|
break;
|
|
case LOG_LEVELS_TYPE:
|
|
unsigned long maskVal;
|
|
if (validateAndGetElement(elementValue, mask) != STATUS_SUCCESS)
|
|
{
|
|
ACE_ERROR ((MY_ERROR ACE_TEXT ("Invalid log level: %s.\n"),
|
|
elementValue.c_str()));
|
|
return status;
|
|
}
|
|
maskVal = mask.getMask();
|
|
if (addSingleElement<unsigned long>(sectionName, elementName, maskVal) != STATUS_SUCCESS)
|
|
{
|
|
return status;
|
|
}
|
|
break;
|
|
case TIME_T_TYPE:
|
|
unsigned int temp;
|
|
if (validateAndGetElement(elementValue, temp) != STATUS_SUCCESS)
|
|
{
|
|
ACE_ERROR ((MY_ERROR ACE_TEXT ("Invalid time type: %s.\n"),
|
|
elementValue.c_str()));
|
|
return status;
|
|
}
|
|
// Loss of information is not expected since the information is supposed to be short.
|
|
// But this should be checked.
|
|
timeVal = (time_t) temp;
|
|
if (addSingleElement<time_t>(sectionName, elementName, timeVal) != STATUS_SUCCESS)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
break;
|
|
case IP_TYPE:
|
|
if (validateIP(elementValue) != STATUS_SUCCESS)
|
|
{
|
|
ACE_ERROR ((MY_ERROR ACE_TEXT ("Invalid host name: %s.\n"),
|
|
elementValue.c_str()));
|
|
return status;
|
|
}
|
|
|
|
if (addSingleElement<ACE_TString>(sectionName, elementName, elementValue) != STATUS_SUCCESS)
|
|
{
|
|
return status;
|
|
}
|
|
// try to add INET if possible
|
|
/*if (addINET(sectionName, elementName, false) != STATUS_SUCCESS)
|
|
{
|
|
return status;
|
|
}*/
|
|
|
|
break;
|
|
case MC_LIST_TYPE:
|
|
|
|
mc_list = getValueChangable<MCList>(sectionName.c_str(), sectionName.c_str());
|
|
if (mc_list == NULL)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
if (mc_list->size() >= MAX_NOTIFICATIONS)
|
|
{
|
|
ACE_ERROR ((MY_DEBUG ACE_TEXT ("Notification list cannot exceed maximum size of %d entries. Skipping notification entry: %s\n"),
|
|
MAX_NOTIFICATIONS , elementValue.c_str()));
|
|
}
|
|
else
|
|
{
|
|
mc_data = new URL_Wrapper();
|
|
if (mc_data == NULL)
|
|
{
|
|
return status;
|
|
}
|
|
if (validateAndGetElement(elementValue, *mc_data) != STATUS_SUCCESS)
|
|
{
|
|
ACE_ERROR ((MY_ERROR ACE_TEXT ("Skipping invalid notification entry: %s.\n"),
|
|
elementValue.c_str()));
|
|
delete mc_data;
|
|
}
|
|
else
|
|
{
|
|
TRY_ACQUIRE_WRITE_GUARD( ACE_RW_Thread_Mutex ,
|
|
lock,
|
|
mc_list->guard());
|
|
if (lock.locked () == 0)
|
|
{
|
|
delete mc_data;
|
|
ACE_ERROR_RETURN((MY_DEBUG ACE_TEXT ("Unable to acquire write mutex on notification list.\n")), status);
|
|
}
|
|
|
|
mc_list->push_back(mc_data);
|
|
}
|
|
}
|
|
break;
|
|
case AUTHERIZED_SERVERS_LIST_TYPE:
|
|
as_data = new ServerData();
|
|
if (as_data == NULL)
|
|
{
|
|
return status;
|
|
}
|
|
if (validateAndGetElement(elementValue, *as_data) != STATUS_SUCCESS)
|
|
{
|
|
ACE_ERROR ((MY_ERROR ACE_TEXT ("Skipping invalid authorized server entry: %s\n"),
|
|
elementValue.c_str()));
|
|
delete as_data;
|
|
}
|
|
else
|
|
{
|
|
as_hash = getValueChangable<AuthServerHash>(sectionName.c_str(), sectionName.c_str());
|
|
if (as_hash == NULL)
|
|
{
|
|
delete as_data;
|
|
return status;
|
|
}
|
|
|
|
// Element value is intentionally inserted here.
|
|
// This means that the TESTED host:port are entered as the key in the hash,
|
|
// while the value holds the needed data about them, including the relevant INET
|
|
|
|
TRY_ACQUIRE_WRITE_GUARD( ACE_RW_Thread_Mutex ,
|
|
lock,
|
|
as_hash->guard());
|
|
if (lock.locked () == 0)
|
|
{
|
|
delete as_data;
|
|
ACE_ERROR_RETURN((MY_DEBUG ACE_TEXT ("Unable to acquire write mutex on authorized servers hash.\n")), status);
|
|
}
|
|
|
|
as_hash->insert(make_pair(elementValue, as_data));
|
|
}
|
|
break;
|
|
default:
|
|
return status;
|
|
break;
|
|
}
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
* Adds an INET type element to the hash according to the given sectionName and elementName.
|
|
* isPort indicates if the given element indicates a port or an ip, by which the indication
|
|
* of the INET is recognized. It may be that an INET object is not currently possible to add, in which
|
|
* case, this is not considered as error (such as in the example that only the port is known)
|
|
* Returns STATUS_FAILURE on failure.
|
|
* Returns STATUS_SUCCESS on success.
|
|
*/
|
|
//STATUS Options::addINET(const ACE_TString §ionName,
|
|
// const ACE_TString &elementName,
|
|
// bool isPort)
|
|
//{
|
|
// STATUS status = STATUS_FAILURE;
|
|
//
|
|
// // Check to see if this is indeed a port and if there is an ip corresponding to it yet
|
|
// // if there is, also add an INET object
|
|
// ACE_TString addition, otherAddition, IPName, IP2Name,PortName,otherAddition2;
|
|
// ACE_TString ipv4 = IPv4;
|
|
// ACE_TString ipv6 = IPv6;
|
|
// if (isPort)
|
|
// {
|
|
// /*
|
|
// if ((elementName.substr(elementName.length() - ipv4.length())).compare(ipv4) == 0)
|
|
// otherAddition = IPv4;
|
|
// else if ((elementName.substr(elementName.length() - ipv6.length())).compare(ipv6) == 0)
|
|
// otherAddition = IPv6;
|
|
// else*/
|
|
// addition = PORT;
|
|
// otherAddition = IPv4;
|
|
// otherAddition2 = IPv6;
|
|
// }
|
|
// else
|
|
// {
|
|
// if ((elementName.substr(elementName.length() - ipv4.length())).compare(ipv4) == 0)
|
|
// addition = IPv4;
|
|
// else if ((elementName.substr(elementName.length() - ipv6.length())).compare(ipv6) == 0)
|
|
// addition = IPv6;
|
|
// else
|
|
// addition = "";
|
|
// addition2 = "";
|
|
// otherAddition = PORT;
|
|
// }
|
|
//
|
|
// if (elementName.length() - addition.length() < 0)
|
|
// {
|
|
// return status;
|
|
// }
|
|
// if ((!addition.is_empty()) && (!otherAddition.is_empty()))
|
|
// {
|
|
// ACE_TString baseName = elementName.substr(STATUS_SUCCESS, elementName.length() - addition.length());
|
|
// ACE_TString otherName = baseName;
|
|
// otherName += otherAddition;
|
|
// if (_element_hash.hasInner(sectionName, otherName))
|
|
// {
|
|
// ACE_INET_Addr address;
|
|
// IPName = baseName;
|
|
// IPName += IPv4;
|
|
// IP2Name = baseName;
|
|
// IP2Name += IPv6;
|
|
// PortName = baseName;
|
|
// PortName += PORT;
|
|
//
|
|
// const unsigned short &port = *getValue<unsigned short>(sectionName.c_str(), PortName.c_str());
|
|
// const ACE_TString &ipv4 = *getValue<ACE_TString>(sectionName.c_str(), IPName.c_str());
|
|
// const ACE_TString &ipv6 = *getValue<ACE_TString>(sectionName.c_str(), IP2Name.c_str());
|
|
// if (address.set(port, ipv4.c_str()) != STATUS_SUCCESS)
|
|
// {
|
|
// return status;
|
|
// }
|
|
// if (addSingleElement<ACE_INET_Addr>(sectionName, baseName + INET4, address) != STATUS_SUCCESS)
|
|
// {
|
|
// return status;
|
|
// }
|
|
// if (address.set(port, ipv6.c_str()) != STATUS_SUCCESS)
|
|
// {
|
|
// return status;
|
|
// }
|
|
// if (addSingleElement<ACE_INET_Addr>(sectionName, baseName + INET6, address) != STATUS_SUCCESS)
|
|
// {
|
|
// return status;
|
|
// }
|
|
// }
|
|
// }
|
|
//
|
|
// status = STATUS_SUCCESS;
|
|
//
|
|
// return status;
|
|
//}
|
|
|
|
/*
|
|
* Checks that the format given (mandatory or optional set by isMandatory), fits the inner hash.
|
|
* i.e: if the hash holding all the data has all the elements it is required off according to
|
|
* the formats (if it does not hold an element that is in the optional format, than its
|
|
* default value is added)
|
|
* This is done after the inner hash is filled.
|
|
* Returns STATUS_FAILURE on failure.
|
|
* Returns STATUS_SUCCESS on success.
|
|
*/
|
|
STATUS Options::checkFormat(const Format * format, bool isMandatory)
|
|
{
|
|
STATUS status = STATUS_FAILURE;
|
|
|
|
if (format == NULL)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
Format::constOuterIter formatIter;
|
|
|
|
auto_ptr<Format::constOuterIter> formatIterP_begin(format -> beginOuters());
|
|
auto_ptr<Format::constOuterIter> formatIterP_end(format -> endOuters());
|
|
if ((formatIterP_begin.get() == NULL) || (formatIterP_end.get() == NULL))
|
|
{
|
|
return status;
|
|
}
|
|
formatIter = * formatIterP_begin;
|
|
|
|
for (; formatIter != *formatIterP_end; formatIter++)
|
|
{
|
|
if (!_element_hash.hasOuter(formatIter->first))
|
|
{
|
|
if (isMandatory)
|
|
{
|
|
ACE_ERROR ((MY_ERROR ACE_TEXT ("Static config file is missing mandatory section: %s.\n"),
|
|
formatIter->first.c_str()));
|
|
return status;
|
|
}
|
|
else
|
|
{
|
|
_element_hash.addOuter(formatIter->first);
|
|
}
|
|
}
|
|
|
|
auto_ptr<Format::constInnerIter> formatInnerIterP_begin(format -> beginInners(formatIter->first));
|
|
auto_ptr<Format::constInnerIter> formatInnerIterP_end(format -> endInners(formatIter->first));
|
|
if ((formatInnerIterP_begin.get() == NULL) || (formatInnerIterP_end.get() == NULL))
|
|
{
|
|
return status;
|
|
}
|
|
Format::constInnerIter formatInnerIter = * formatInnerIterP_begin;
|
|
|
|
for (; formatInnerIter != *formatInnerIterP_end; formatInnerIter++)
|
|
{
|
|
if (!_element_hash.hasInner(formatIter->first, formatInnerIter->first))
|
|
{
|
|
if (isMandatory)
|
|
{
|
|
ACE_ERROR ((MY_ERROR ACE_TEXT ("Static config file is missing mandatory element: %s in section: %s.\n"),
|
|
formatInnerIter->first.c_str(), formatIter->first.c_str()));
|
|
return status;
|
|
}
|
|
else
|
|
{
|
|
Element_Type_Enum_and_Default_Val * element =
|
|
(Element_Type_Enum_and_Default_Val *) formatInnerIter ->second;
|
|
ACE_TString typeVal = element->getTypeVal();
|
|
if (addToElementHash(formatIter->first, formatInnerIter->first,
|
|
element->getElementType(), typeVal) != STATUS_SUCCESS)
|
|
{
|
|
ACE_ERROR ((MY_ERROR ACE_TEXT ("Default element used for element: %s in section: %s is incompatible with expected type.\n"),
|
|
formatInnerIter->first.c_str(), formatIter->first.c_str()));
|
|
return status;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
* Reads and parses all external files, and enters them to the element hash according
|
|
* their data.
|
|
* Returns -1 on failure.
|
|
* Otherwise, returns the amount of files that were read (files that were changed).
|
|
*/
|
|
int Options::read_all_external_files()
|
|
{
|
|
int ret = 0;
|
|
|
|
ElementHash::constInnerIter hashInnerIter;
|
|
Element_Type_Enum * elementType = NULL;
|
|
|
|
// Iterate on Files section
|
|
auto_ptr<ElementHash::constInnerIter> hashInnerIterP_begin(_element_hash.beginInners(FILES));
|
|
auto_ptr<ElementHash::constInnerIter> hashInnerIterP_end(_element_hash.endInners(FILES));
|
|
if ((hashInnerIterP_begin.get() == NULL) || (hashInnerIterP_end.get() == NULL))
|
|
{
|
|
return STATUS_FAILURE;
|
|
}
|
|
hashInnerIter = * hashInnerIterP_begin;
|
|
for (; hashInnerIter != *hashInnerIterP_end; hashInnerIter++)
|
|
{
|
|
const ACE_TString * fileName = getValue<ACE_TString>(FILES, hashInnerIter->first.c_str());
|
|
if (fileName == NULL)
|
|
{
|
|
return STATUS_FAILURE;
|
|
}
|
|
|
|
ACE_stat fileStats;
|
|
ACE_OS::stat(fileName->c_str(), &fileStats);
|
|
map< ACE_TString, time_t, ACE_TString_compare_no_toUpper >::const_iterator iter =
|
|
_extModifTimeMap.find(*fileName);
|
|
// If it is the first time, then the file name is not in the map, and should
|
|
// be entered with the proper value.
|
|
// If it is, than its last changed date should be checked.
|
|
if ((iter == _extModifTimeMap.end()) ||
|
|
(_extModifTimeMap[*fileName] != fileStats.st_mtime))
|
|
{
|
|
if (obtainElementType(_format_static_mandatory, _format_static_optional,
|
|
FILES, hashInnerIter->first, &elementType) != STATUS_SUCCESS)
|
|
{
|
|
return STATUS_FAILURE;
|
|
}
|
|
|
|
List_Parser parser;
|
|
vector<ACE_TString> vec;
|
|
if (parser.parseItemList(fileName -> c_str(), vec) != PARSER_STATUS_SUCCESS)
|
|
{
|
|
return STATUS_FAILURE;
|
|
}
|
|
|
|
STATUS tempStat;
|
|
if ((tempStat = build_element_hash_ext_from_vector(vec, hashInnerIter->first, elementType)) != STATUS_SUCCESS)
|
|
{
|
|
if (tempStat == STATUS_LOCK_FAILURE)
|
|
{
|
|
continue;
|
|
}
|
|
return STATUS_FAILURE;
|
|
}
|
|
// If reading the file was successful, than set a new change time.
|
|
_extModifTimeMap[*fileName] = fileStats.st_mtime;
|
|
++ret;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Adds an element to the element hash according to an external file which was parsed to a vector.
|
|
* The vector reference is the vector which holds the parsed information.
|
|
* The section name indicates which section the new element is supposed to be in.
|
|
* The element type indicates the needed element type
|
|
* Note: A single element (in the final hash) is provided per file (usually a list or a hash)
|
|
* Returns STATUS_FAILURE on failure.
|
|
* Returns STATUS_SUCCESS on success.
|
|
*/
|
|
STATUS Options::build_element_hash_ext_from_vector(const vector<ACE_TString> &vec,
|
|
const ACE_TString §ionName,
|
|
Element_Type_Enum * elementType)
|
|
{
|
|
STATUS status = STATUS_FAILURE;
|
|
|
|
if (elementType == NULL)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
// First, delete the previous element that may exist in that location
|
|
if (!_element_hash.hasInner(sectionName, sectionName))
|
|
{
|
|
BaseElement * elem;
|
|
switch(elementType->getElementType())
|
|
{
|
|
case MC_LIST_TYPE:
|
|
elem = new Element<MCList>();
|
|
if (elem == NULL)
|
|
{
|
|
return status;
|
|
}
|
|
break;
|
|
case AUTHERIZED_SERVERS_LIST_TYPE:
|
|
elem = new Element<AuthServerHash>();
|
|
if (elem == NULL)
|
|
{
|
|
return status;
|
|
}
|
|
break;
|
|
default:
|
|
return status;
|
|
}
|
|
|
|
_element_hash.addInner(sectionName, sectionName, elem);
|
|
}
|
|
else
|
|
// If it does exist, than clear its values
|
|
// (since every time we read the external files again, we start from scratch).
|
|
{
|
|
switch(elementType->getElementType())
|
|
{
|
|
case MC_LIST_TYPE:
|
|
{
|
|
MCList * mc_list = NULL;
|
|
mc_list = getValueChangable<MCList>(sectionName.c_str(), sectionName.c_str());
|
|
if (mc_list == NULL)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
TRY_ACQUIRE_WRITE_GUARD( ACE_RW_Thread_Mutex ,
|
|
lock,
|
|
mc_list->guard());
|
|
if (lock.locked () == 0)
|
|
{
|
|
ACE_ERROR_RETURN((MY_DEBUG ACE_TEXT ("Unable to acquire write mutex on notification list.\n")), STATUS_LOCK_FAILURE);
|
|
}
|
|
|
|
mc_list->clearList();
|
|
}
|
|
break;
|
|
case AUTHERIZED_SERVERS_LIST_TYPE:
|
|
{
|
|
AuthServerHash * authHash = NULL;
|
|
authHash = getValueChangable<AuthServerHash>(sectionName.c_str(), sectionName.c_str());
|
|
if (authHash == NULL)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
TRY_ACQUIRE_WRITE_GUARD( ACE_RW_Thread_Mutex ,
|
|
lock,
|
|
authHash->guard());
|
|
if (lock.locked () == 0)
|
|
{
|
|
ACE_ERROR_RETURN((MY_DEBUG ACE_TEXT ("Unable to acquire write mutex on authorized servers hash.\n")), STATUS_LOCK_FAILURE);
|
|
}
|
|
|
|
authHash->clearHash();
|
|
}
|
|
break;
|
|
default:
|
|
return status;
|
|
}
|
|
}
|
|
|
|
ACE_TString elementName, elementValue;
|
|
|
|
vector< ACE_TString >::const_iterator iter;
|
|
for (iter = vec.begin(); iter != vec.end(); iter++)
|
|
{
|
|
// The element name does not matter => just leave it blank
|
|
elementValue = *iter;
|
|
if (addToElementHash(sectionName, elementName,
|
|
elementType->getElementType(), elementValue) != STATUS_SUCCESS)
|
|
{
|
|
return status;
|
|
}
|
|
}
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
* Obtains a single elements' type according to the given formats. Puts a pointer to the
|
|
* element type in **elementType.
|
|
* Returns STATUS_FAILURE on failure.
|
|
* Returns STATUS_SUCCESS on success.
|
|
*/
|
|
STATUS Options::obtainElementType(const Format * mandatory_format, const Format * optional_format,
|
|
const ACE_TString §ionName, const ACE_TString &elementName,
|
|
Element_Type_Enum ** elementType)
|
|
{
|
|
STATUS status = STATUS_FAILURE;
|
|
|
|
if (mandatory_format == NULL ||
|
|
optional_format == NULL ||
|
|
elementType == NULL)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
// Check if element is in mandatory first
|
|
if (mandatory_format -> hasInner(sectionName, elementName))
|
|
{
|
|
mandatory_format -> getValue(sectionName, elementName, elementType);
|
|
}
|
|
// Now check with optional
|
|
else
|
|
{
|
|
if (optional_format -> hasInner(sectionName, elementName))
|
|
{
|
|
optional_format -> getValue(sectionName, elementName, elementType);
|
|
}
|
|
// Not in optional or mandatory - considered an error
|
|
else
|
|
{
|
|
ACE_ERROR ((MY_ERROR ACE_TEXT ("Element: %s in section: %s does not appear in accepted formats\n"),
|
|
elementName.c_str(), sectionName.c_str()));
|
|
return status;
|
|
}
|
|
}
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
* Deletes an element from the element hash (deleting the element itself and removing
|
|
* it from the canonical element hash).
|
|
* Returns STATUS_FAILURE on failure.
|
|
* Returns STATUS_SUCCESS on success.
|
|
*/
|
|
STATUS Options::deleteElement(const ACE_TString §ionName, const ACE_TString &elementName)
|
|
{
|
|
STATUS status = STATUS_FAILURE;
|
|
|
|
if (deleteElementContent(sectionName, elementName) != STATUS_SUCCESS)
|
|
{
|
|
return status;
|
|
}
|
|
if (_element_hash.deleteElement(sectionName, elementName) != STATUS_SUCCESS)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
* Deletes an element from the element hash (deleting the element itself but not removing
|
|
* it from the canonical element hash).
|
|
* Returns STATUS_FAILURE on failure.
|
|
* Returns STATUS_SUCCESS on success.
|
|
*/
|
|
STATUS Options::deleteElementContent(const ACE_TString §ionName, const ACE_TString &elementName)
|
|
{
|
|
STATUS status = STATUS_FAILURE;
|
|
|
|
BaseElement * base = NULL;
|
|
if ((_element_hash.getValue(sectionName, elementName, &base) != STATUS_SUCCESS) || (base == NULL))
|
|
{
|
|
return status;
|
|
}
|
|
delete base;
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
return status;
|
|
}
|