mirror of
https://github.com/RetroShare/RetroShare.git
synced 2024-10-01 02:35:48 -04:00
b80aef1228
This avoids that an attacker that captures a broadcast hash request can also ask for the file. This needed to add back explicit sources in SearchDialog and private chat transfer. I dynamically search for sources in file lists just before calling FileRequest. When RS links anchorClick() will work properly with Qt, we can remove the search flag "EXTRA" from the tunnel digging in p3turtle.cc, otherwise, people having this bug can't transfer files in private chat by copy+paste of a RS link. Also: - added missing mutexes in search requests into fimonitor.cc - suppressed some debug info in connect manager - added check for write fails when dumping config files git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@3027 b45a01b8-16f6-495d-af2f-9b41ad6348cc
991 lines
24 KiB
C++
991 lines
24 KiB
C++
/*
|
|
* libretroshare/src/pqi: p3cfgmgr.cc
|
|
*
|
|
* 3P/PQI network interface for RetroShare.
|
|
*
|
|
* Copyright 2007-2008 by Robert Fernie.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License Version 2 as published by the Free Software Foundation.
|
|
*
|
|
* This library 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
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
|
* USA.
|
|
*
|
|
* Please report all bugs and problems to "retroshare@lunamutt.com".
|
|
*
|
|
*/
|
|
|
|
#include "util/rsdir.h"
|
|
#include "rsiface/rspeers.h"
|
|
#include "pqi/p3cfgmgr.h"
|
|
#include "pqi/authssl.h"
|
|
#include "pqi/pqibin.h"
|
|
#include "pqi/pqistore.h"
|
|
#include "pqi/pqinotify.h"
|
|
#include <errno.h>
|
|
#include <util/rsdiscspace.h>
|
|
|
|
#include "serialiser/rsconfigitems.h"
|
|
|
|
/*
|
|
#define CONFIG_DEBUG 1
|
|
*/
|
|
#define BACKEDUP_SAVE
|
|
|
|
|
|
p3ConfigMgr::p3ConfigMgr(std::string dir, std::string fname, std::string signame)
|
|
:basedir(dir), metafname(fname), metasigfname(signame),
|
|
mConfigSaveActive(true)
|
|
{
|
|
}
|
|
|
|
void p3ConfigMgr::tick()
|
|
{
|
|
bool toSave = false;
|
|
|
|
{
|
|
RsStackMutex stack(cfgMtx); /***** LOCK STACK MUTEX ****/
|
|
|
|
/* iterate through and check if any have changed */
|
|
std::map<uint32_t, pqiConfig *>::iterator it;
|
|
for(it = configs.begin(); it != configs.end(); it++)
|
|
{
|
|
if (it->second->HasConfigChanged(0))
|
|
{
|
|
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "p3ConfigMgr::tick() Config Changed - Element: ";
|
|
std::cerr << it->first;
|
|
std::cerr << std::endl;
|
|
#endif
|
|
|
|
toSave = true;
|
|
}
|
|
}
|
|
|
|
/* disable saving before exit */
|
|
if (!mConfigSaveActive)
|
|
{
|
|
toSave = false;
|
|
}
|
|
}
|
|
|
|
if (toSave)
|
|
{
|
|
saveConfiguration();
|
|
}
|
|
}
|
|
|
|
|
|
void p3ConfigMgr::saveConfiguration()
|
|
{
|
|
if(!RsDiscSpace::checkForDiscSpace(RS_CONFIG_DIRECTORY))
|
|
return ;
|
|
|
|
RsStackMutex stack(cfgMtx); /***** LOCK STACK MUTEX ****/
|
|
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "p3ConfigMgr::saveConfiguration()";
|
|
std::cerr << std::endl;
|
|
#endif
|
|
|
|
RsConfigKeyValueSet *item = new RsConfigKeyValueSet();
|
|
|
|
std::map<uint32_t, pqiConfig *>::iterator it;
|
|
for(it = configs.begin(); it != configs.end(); it++)
|
|
{
|
|
if (it->second->HasConfigChanged(1))
|
|
{
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "p3ConfigMgr::saveConfiguration() Saving Element: ";
|
|
std::cerr << it->first;
|
|
std::cerr << std::endl;
|
|
#endif
|
|
it->second->saveConfiguration();
|
|
}
|
|
/* save metaconfig */
|
|
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "p3ConfigMgr::saveConfiguration() Element: ";
|
|
std::cerr << it->first << " Hash: " << it->second->Hash();
|
|
std::cerr << std::endl;
|
|
#endif
|
|
if (it->second->Hash() == "")
|
|
{
|
|
/* skip if no hash */
|
|
continue;
|
|
}
|
|
|
|
RsTlvKeyValue kv;
|
|
{
|
|
std::ostringstream out;
|
|
out << it->first;
|
|
kv.key = out.str();
|
|
}
|
|
kv.value = it->second->Hash();
|
|
item->tlvkvs.pairs.push_back(kv);
|
|
}
|
|
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "p3ConfigMgr::saveConfiguration() Complete MetaConfigItem: ";
|
|
std::cerr << std::endl;
|
|
item->print(std::cerr, 20);
|
|
|
|
#endif
|
|
/* construct filename */
|
|
std::string fname = basedir;
|
|
std::string sign_fname = basedir;
|
|
std::string fname_backup, sign_fname_backup; // back up files
|
|
|
|
if (basedir != "")
|
|
{
|
|
fname += "/";
|
|
sign_fname += "/";
|
|
}
|
|
|
|
fname += metafname;
|
|
sign_fname += metasigfname;
|
|
fname_backup = fname + ".tmp";
|
|
sign_fname_backup = sign_fname + ".tmp";
|
|
|
|
/* Write the data to a stream */
|
|
uint32_t bioflags = BIN_FLAGS_WRITEABLE;
|
|
BinMemInterface *configbio = new BinMemInterface(1000, bioflags);
|
|
RsSerialiser *rss = new RsSerialiser();
|
|
rss->addSerialType(new RsGeneralConfigSerialiser());
|
|
pqistore store(rss, "CONFIG", configbio, BIN_FLAGS_WRITEABLE);
|
|
|
|
store.SendItem(item);
|
|
|
|
/* sign data */
|
|
std::string signature;
|
|
AuthSSL::getAuthSSL()->SignData(configbio->memptr(), configbio->memsize(), signature);
|
|
|
|
/* write signature to configuration */
|
|
BinMemInterface *signbio = new BinMemInterface(signature.c_str(),
|
|
signature.length(), BIN_FLAGS_READABLE);
|
|
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "p3ConfigMgr::saveConfiguration() MetaFile Signature:";
|
|
std::cerr << std::endl;
|
|
std::cerr << signature;
|
|
std::cerr << std::endl;
|
|
#endif
|
|
|
|
// begin two pass save
|
|
backedUpFileSave(fname, fname_backup, sign_fname, sign_fname_backup, configbio, signbio);
|
|
|
|
delete signbio;
|
|
}
|
|
|
|
bool p3ConfigMgr::backedUpFileSave(const std::string& fname, const std::string& fname_backup, const std::string& sign_fname,
|
|
const std::string& sign_fname_backup, BinMemInterface* configbio, BinMemInterface* signbio){
|
|
|
|
FILE *file = NULL, *sign = NULL;
|
|
char *config_buff=NULL, *sign_buff=NULL;
|
|
int size_file=0, size_sign=0;
|
|
|
|
// begin two pass saving by writing to back up file instead
|
|
if (!configbio->writetofile(fname_backup.c_str()) || !signbio->writetofile(sign_fname_backup.c_str()))
|
|
{
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "p3ConfigMgr::backedupFileSave() Failed write to Backup MetaFiles " << fname_backup
|
|
<< " and " << sign_fname_backup;
|
|
std::cerr << std::endl;
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "p3Config::backedUpFileSave() Save file and keeps a back up " << std::endl;
|
|
#endif
|
|
|
|
// open file from which to collect buffer
|
|
file = fopen(fname.c_str(), "rb");
|
|
sign = fopen(sign_fname.c_str(), "rb");
|
|
|
|
// if failed then create files
|
|
if((file == NULL) || (sign == NULL)){
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "p3Config::backedUpFileSave() failed to open meta files " << fname << std::endl;
|
|
#endif
|
|
|
|
file = fopen(fname.c_str(), "wb");
|
|
sign = fopen(sign_fname.c_str(), "wb");
|
|
|
|
if((file == NULL) || (sign == NULL)){
|
|
std::cerr << "p3Config::backedUpFileSave() failed to open backup meta files" << fname_backup << std::endl;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
//determine file size
|
|
fseek(file, 0L, SEEK_END);
|
|
size_file = ftell(file);
|
|
fseek(file, 0L, SEEK_SET);
|
|
|
|
fseek(sign, 0L, SEEK_END);
|
|
size_sign = ftell(sign);
|
|
fseek(sign, 0L, SEEK_SET);
|
|
|
|
if((size_file) > 0 && (size_sign > 0)){
|
|
//read this into a buffer
|
|
config_buff = new char[size_file];
|
|
fread(config_buff, 1, size_file, file);
|
|
|
|
//read this into a buffer
|
|
sign_buff = new char[size_sign];
|
|
fread(sign_buff, 1, size_sign, sign);
|
|
}
|
|
|
|
fclose(file);
|
|
fclose(sign);
|
|
|
|
// rename back-up to current file
|
|
if(!RsDirUtil::renameFile(fname_backup, fname) || !RsDirUtil::renameFile(sign_fname_backup, sign_fname)){
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "p3Config::backedUpFileSave() Failed to rename backup meta files: " << std::endl
|
|
<< fname_backup << " to " << fname << std::endl
|
|
<< sign_fname_backup << " to " << sign_fname << std::endl;
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
if((size_file) > 0 && (size_sign > 0)){
|
|
|
|
// now write actual back-up file
|
|
file = fopen(fname_backup.c_str(), "wb");
|
|
sign = fopen(sign_fname_backup.c_str(), "wb");
|
|
|
|
if((file == NULL) || (sign == NULL)){
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "p3Config::backedUpFileSave() fopen failed for file: " << fname_backup << std::endl;
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
if(size_file != fwrite(config_buff,1, size_file, file))
|
|
getPqiNotify()->AddSysMessage(0, RS_SYS_WARNING, "Write error", "Error while writing backup configuration file " + fname_backup + "\nIs your disc full or out of quota ?");
|
|
|
|
if(size_sign != fwrite(sign_buff, 1, size_sign, sign))
|
|
getPqiNotify()->AddSysMessage(0, RS_SYS_WARNING, "Write error", "Error while writing main signature file " + sign_fname_backup + "\nIs your disc full or out of quota ?");
|
|
|
|
fclose(file);
|
|
fclose(sign);
|
|
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "p3Config::backedUpFileSave() finished backed up save. " << std::endl;
|
|
#endif
|
|
|
|
delete[] config_buff;
|
|
delete[] sign_buff;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void p3ConfigMgr::loadConfiguration()
|
|
{
|
|
RsStackMutex stack(cfgMtx); /***** LOCK STACK MUTEX ****/
|
|
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "p3ConfigMgr::loadConfiguration()";
|
|
std::cerr << std::endl;
|
|
#endif
|
|
|
|
/* construct filename */
|
|
std::string fname = basedir;
|
|
std::string sign_fname = basedir;
|
|
std::string fname_backup, sign_fname_backup;
|
|
|
|
if (basedir != "")
|
|
{
|
|
fname += "/";
|
|
sign_fname += "/";
|
|
}
|
|
|
|
fname += metafname;
|
|
sign_fname += metasigfname;
|
|
|
|
// temporary files
|
|
fname_backup = fname + ".tmp";
|
|
sign_fname_backup = sign_fname + ".tmp";
|
|
|
|
BinMemInterface* membio = new BinMemInterface(1000, BIN_FLAGS_READABLE);
|
|
|
|
// Will attempt to get signature first from meta file then if that fails try temporary meta files, these will correspond to temp configs
|
|
bool pass = getSignAttempt(fname, sign_fname, membio);
|
|
|
|
// if first attempt fails then try and temporary files
|
|
if(!pass){
|
|
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "\np3ConfigMgr::loadConfiguration(): Trying to load METACONFIG item and METASIGN with temporary files";
|
|
std::cerr << std::endl;
|
|
#endif
|
|
|
|
pass = getSignAttempt(fname_backup, sign_fname_backup , membio);
|
|
|
|
if(!pass){
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "\np3ConfigMgr::loadConfiguration(): failed to load METACONFIG item and METASIGN";
|
|
std::cerr << std::endl;
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
membio->fseek(0); /* go back to start of file */
|
|
|
|
RsSerialiser *rss = new RsSerialiser();
|
|
rss->addSerialType(new RsGeneralConfigSerialiser());
|
|
pqistore stream(rss, "CONFIG", membio, BIN_FLAGS_READABLE);
|
|
|
|
RsItem *rsitem = stream.GetItem();
|
|
|
|
RsConfigKeyValueSet *item = dynamic_cast<RsConfigKeyValueSet *>(rsitem);
|
|
if (!item)
|
|
{
|
|
delete rsitem;
|
|
return;
|
|
}
|
|
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "p3ConfigMgr::loadConfiguration() Loaded MetaConfigItem: ";
|
|
std::cerr << std::endl;
|
|
item->print(std::cerr, 20);
|
|
|
|
#endif
|
|
|
|
/* extract info from KeyValueSet */
|
|
std::list<RsTlvKeyValue>::iterator it;
|
|
for(it = item->tlvkvs.pairs.begin(); it != item->tlvkvs.pairs.end(); it++)
|
|
{
|
|
/* find the configuration */
|
|
uint32_t confId = atoi(it->key.c_str());
|
|
std::string hashin = it->value;
|
|
|
|
/*********************** HACK TO CHANGE CACHE CONFIG ID *********
|
|
* REMOVE IN A MONTH OR TWO
|
|
*/
|
|
|
|
if (confId == CONFIG_TYPE_CACHE_OLDID)
|
|
{
|
|
confId = CONFIG_TYPE_CACHE;
|
|
}
|
|
|
|
/*********************** HACK TO CHANGE CACHE CONFIG ID *********/
|
|
|
|
std::map<uint32_t, pqiConfig *>::iterator cit;
|
|
cit = configs.find(confId);
|
|
if (cit != configs.end())
|
|
{
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "p3ConfigMgr::loadConfiguration() Element: ";
|
|
std::cerr << confId << " Hash: " << hashin;
|
|
std::cerr << std::endl;
|
|
#endif
|
|
(cit->second)->loadConfiguration(hashin);
|
|
/* force config to NOT CHANGED */
|
|
cit->second->HasConfigChanged(0);
|
|
cit->second->HasConfigChanged(1);
|
|
}
|
|
}
|
|
|
|
delete item;
|
|
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "p3ConfigMgr::loadConfiguration() Done!";
|
|
std::cerr << std::endl;
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
bool p3ConfigMgr::getSignAttempt(std::string& metaConfigFname, std::string& metaSignFname, BinMemInterface* membio){
|
|
|
|
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "p3ConfigMgr::getSignAttempt() metaConfigFname : " << metaConfigFname;
|
|
std::cerr << std::endl;
|
|
std::cerr << "p3ConfigMgr::getSignAttempt() metaSignFname : " << metaSignFname;
|
|
std::cerr << std::endl;
|
|
#endif
|
|
|
|
/* read signature */
|
|
BinMemInterface *signbio = new BinMemInterface(1000, BIN_FLAGS_READABLE);
|
|
|
|
if (!signbio->readfromfile(metaSignFname.c_str()))
|
|
{
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "p3ConfigMgr::getSignAttempt() Failed to Load MetaSignFile";
|
|
std::cerr << std::endl;
|
|
#endif
|
|
|
|
/* HACK to load the old one (with the wrong directory)
|
|
* THIS SHOULD BE REMOVED IN A COUPLE OF VERSIONS....
|
|
* ONLY HERE TO CORRECT BAD MISTAKE IN EARLIER VERSIONS.
|
|
*/
|
|
|
|
metaSignFname = metasigfname;
|
|
metaConfigFname = metafname;
|
|
|
|
if (!signbio->readfromfile(metaSignFname.c_str()))
|
|
{
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "p3ConfigMgr::getSignAttempt() HACK: Failed to Load ALT MetaSignFile";
|
|
std::cerr << std::endl;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "p3ConfigMgr::getSignAttempt() HACK: Loaded ALT MetaSignFile";
|
|
std::cerr << std::endl;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
std::string oldsignature((char *) signbio->memptr(), signbio->memsize());
|
|
delete signbio;
|
|
|
|
|
|
|
|
if (!membio->readfromfile(metaConfigFname.c_str()))
|
|
{
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "p3ConfigMgr::getSignAttempt() Failed to Load MetaFile";
|
|
std::cerr << std::endl;
|
|
#endif
|
|
// delete membio;
|
|
// return ;
|
|
}
|
|
|
|
/* get signature */
|
|
std::string signature;
|
|
AuthSSL::getAuthSSL()->SignData(membio->memptr(), membio->memsize(), signature);
|
|
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "p3ConfigMgr::getSignAttempt() New MetaFile Signature:";
|
|
std::cerr << std::endl;
|
|
std::cerr << signature;
|
|
std::cerr << std::endl;
|
|
#endif
|
|
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "p3ConfigMgr::getSignAttempt() Orig MetaFile Signature:";
|
|
std::cerr << std::endl;
|
|
std::cerr << oldsignature;
|
|
std::cerr << std::endl;
|
|
#endif
|
|
|
|
if (signature != oldsignature)
|
|
{
|
|
/* Failed */
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "p3ConfigMgr::getSignAttempt() Signature Check Failed";
|
|
std::cerr << std::endl;
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "p3ConfigMgr::getSignAttempt() Signature Check Passed!";
|
|
std::cerr << std::endl;
|
|
#endif
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
void p3ConfigMgr::addConfiguration(std::string file, pqiConfig *conf)
|
|
{
|
|
RsStackMutex stack(cfgMtx); /***** LOCK STACK MUTEX ****/
|
|
|
|
/* construct filename */
|
|
std::string filename = basedir;
|
|
if (basedir != "")
|
|
{
|
|
filename += "/";
|
|
}
|
|
filename += file;
|
|
|
|
conf->setFilename(filename);
|
|
configs[conf->Type()] = conf;
|
|
}
|
|
|
|
|
|
void p3ConfigMgr::completeConfiguration()
|
|
{
|
|
saveConfiguration();
|
|
|
|
RsStackMutex stack(cfgMtx); /***** LOCK STACK MUTEX ****/
|
|
mConfigSaveActive = false;
|
|
}
|
|
|
|
p3Config::p3Config(uint32_t t)
|
|
:pqiConfig(t)
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
bool p3Config::loadConfiguration(std::string &loadHash)
|
|
{
|
|
bool pass = false;
|
|
std::string cfg_fname = Filename();
|
|
std::string cfg_fname_backup = cfg_fname + ".tmp";
|
|
std::string hashstr;
|
|
std::list<RsItem *> load;
|
|
|
|
#ifdef CONFIG_DEBUG
|
|
std::string success_fname = cfg_fname;
|
|
std::cerr << "p3Config::loadConfiguration(): Attempting to load configuration file" << cfg_fname << std::endl;
|
|
#endif
|
|
|
|
pass = getHashAttempt(loadHash, hashstr, cfg_fname, load);
|
|
|
|
if(!pass){
|
|
load.clear();
|
|
pass = getHashAttempt(loadHash, hashstr, cfg_fname_backup, load);
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "p3Config::loadConfiguration() ERROR: Failed to get Hash from " << success_fname << std::endl;
|
|
success_fname = cfg_fname_backup;
|
|
#endif
|
|
|
|
if(!pass){
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "p3Config::loadConfiguration() ERROR: Failed to get Hash from " << success_fname << std::endl;
|
|
#endif
|
|
return false;
|
|
}
|
|
}
|
|
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "p3Config::loadConfiguration(): SUCCESS: configuration file loaded" << success_fname << std::endl;
|
|
#endif
|
|
|
|
setHash(hashstr);
|
|
return loadList(load);
|
|
}
|
|
|
|
|
|
|
|
|
|
bool p3Config::getHashAttempt(const std::string& loadHash, std::string& hashstr,const std::string& cfg_fname,
|
|
std::list<RsItem *>& load){
|
|
|
|
std::list<RsItem *>::iterator it;
|
|
|
|
uint32_t bioflags = BIN_FLAGS_HASH_DATA | BIN_FLAGS_READABLE;
|
|
uint32_t stream_flags = BIN_FLAGS_READABLE;
|
|
|
|
BinInterface *bio = new BinFileInterface(cfg_fname.c_str(), bioflags);
|
|
pqistore stream(setupSerialiser(), "CONFIG", bio, stream_flags);
|
|
RsItem *item = NULL;
|
|
|
|
while(NULL != (item = stream.GetItem()))
|
|
{
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "p3Config::loadConfiguration() loaded item:";
|
|
std::cerr << std::endl;
|
|
item->print(std::cerr, 0);
|
|
std::cerr << std::endl;
|
|
#endif
|
|
load.push_back(item);
|
|
}
|
|
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "p3Config::loadConfiguration() loaded " << load.size();
|
|
std::cerr << " Elements from File: " << cfg_fname;
|
|
std::cerr << std::endl;
|
|
#endif
|
|
|
|
/* check hash */
|
|
hashstr = bio->gethash();
|
|
|
|
// if hash then atmpt load with temporary file
|
|
if (hashstr != loadHash)
|
|
{
|
|
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "p3Config::loadConfiguration() ERROR: Hash != MATCHloaded";
|
|
std::cerr << std::endl;
|
|
#endif
|
|
|
|
/* bad load */
|
|
for(it = load.begin(); it != load.end(); it++)
|
|
{
|
|
delete (*it);
|
|
}
|
|
|
|
setHash("");
|
|
|
|
return false;
|
|
}
|
|
//delete bio;
|
|
return true;
|
|
}
|
|
|
|
|
|
bool p3Config::saveConfiguration()
|
|
{
|
|
|
|
bool cleanup = true;
|
|
std::list<RsItem *> toSave = saveList(cleanup);
|
|
|
|
|
|
std::string cfg_fname = Filename(); // get configuration file name
|
|
std::string cfg_fname_backup = Filename()+".tmp"; // backup file for two pass save
|
|
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "Writting p3config file " << cfg_fname << std::endl ;
|
|
std::cerr << "p3Config::saveConfiguration() toSave " << toSave.size();
|
|
std::cerr << " Elements to File: " << cfg_fname;
|
|
std::cerr << std::endl;
|
|
#endif
|
|
|
|
// saves current config and keeps back-up (old configuration)
|
|
if(!backedUpFileSave(cfg_fname, cfg_fname_backup, toSave, cleanup)){
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "p3Config::saveConfiguration(): Failed to save file" << std::endl;
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
saveDone(); // callback to inherited class to unlock any Mutexes protecting saveList() data
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool p3Config::backedUpFileSave(const std::string& cfg_fname, const std::string& cfg_fname_backup, std::list<RsItem* >& itemList,
|
|
bool cleanup){
|
|
|
|
uint32_t bioflags = BIN_FLAGS_HASH_DATA | BIN_FLAGS_WRITEABLE;
|
|
uint32_t stream_flags = BIN_FLAGS_WRITEABLE;
|
|
bool written = true;
|
|
FILE* cfg_file = NULL;
|
|
char* buff=NULL;
|
|
int size_file = 0;
|
|
|
|
if (!cleanup)
|
|
stream_flags |= BIN_FLAGS_NO_DELETE;
|
|
|
|
BinInterface *bio = new BinFileInterface(cfg_fname_backup.c_str(), bioflags);
|
|
pqistore *stream = new pqistore(setupSerialiser(), "CONFIG", bio, stream_flags);
|
|
|
|
std::list<RsItem *>::iterator it;
|
|
|
|
for(it = itemList.begin(); it != itemList.end(); it++)
|
|
{
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "p3Config::backedUpFileSave() save item:";
|
|
std::cerr << std::endl;
|
|
(*it)->print(std::cerr, 0);
|
|
std::cerr << std::endl;
|
|
#endif
|
|
written = written && stream->SendItem(*it);
|
|
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "p3Config::backedUpFileSave() saved ";
|
|
#endif
|
|
|
|
}
|
|
|
|
/* store the hash */
|
|
setHash(bio->gethash());
|
|
|
|
// bio is taken care of in stream's destructor
|
|
delete stream;
|
|
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "p3Config::backedUpFileSave() Save file and keeps a back up " << std::endl;
|
|
#endif
|
|
|
|
// open file from which to collect buffer
|
|
cfg_file = fopen(cfg_fname.c_str(), "rb");
|
|
|
|
// if it fails to open, create file,but back-up file will now be empty
|
|
if(cfg_file == NULL){
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "p3Config::backedUpFileSave() fopen failed for file: " << cfg_fname << std::endl;
|
|
#endif
|
|
|
|
cfg_file = fopen(cfg_fname.c_str(), "wb");
|
|
|
|
if(cfg_file == NULL)
|
|
std::cerr << "p3Config::backedUpFileSave() fopen failed for file:" << cfg_fname << std::endl;
|
|
}
|
|
|
|
//determine file size
|
|
fseek(cfg_file, 0L, SEEK_END);
|
|
size_file = ftell(cfg_file);
|
|
fseek(cfg_file, 0L, SEEK_SET);
|
|
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "p3Config::backedUpFileSave(): Size of file: " << size_file << std::endl;
|
|
#endif
|
|
|
|
// no point continuing, empty files all have same hash
|
|
if(size_file > 0){
|
|
|
|
//read this into a data buffer
|
|
buff = new char[size_file];
|
|
fread(buff, 1, size_file, cfg_file);
|
|
}
|
|
|
|
fclose(cfg_file);
|
|
|
|
// rename back-up to current file, if this fails should return false hash's will not match at startup
|
|
if(!RsDirUtil::renameFile(cfg_fname_backup, cfg_fname)){
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "p3Config::backedUpFileSave() Failed to rename file" << cfg_fname_backup << " to "
|
|
<< cfg_fname << std::endl;
|
|
#endif
|
|
written &= false; // at least one file save should be successful
|
|
}
|
|
|
|
if(size_file > 0)
|
|
{
|
|
|
|
// now write actual back-up file
|
|
cfg_file = fopen(cfg_fname_backup.c_str(), "wb");
|
|
|
|
if(cfg_file == NULL){
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "p3Config::backedUpFileSave() fopen failed for file: " << cfg_fname_backup << std::endl;
|
|
#endif
|
|
}
|
|
|
|
if(size_file != fwrite(buff, 1, size_file, cfg_file))
|
|
{
|
|
getPqiNotify()->AddSysMessage(0, RS_SYS_WARNING, "Write error", "Error while writing backup configuration file " + cfg_fname_backup + "\nIs your disc full or out of quota ?");
|
|
fclose(cfg_file);
|
|
return false ;
|
|
}
|
|
|
|
|
|
fclose(cfg_file);
|
|
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "p3Config::backedUpFileSave() finished backed up save. " << std::endl;
|
|
#endif
|
|
|
|
|
|
delete[] buff;
|
|
written |= true; // either backup or current file should have been saved
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "p3Config::backedUpFileSave() finished backed up save. " << std::endl;
|
|
#endif
|
|
|
|
return written;
|
|
}
|
|
|
|
|
|
/**************************** CONFIGURATION CLASSES ********************/
|
|
|
|
p3GeneralConfig::p3GeneralConfig()
|
|
:p3Config(CONFIG_TYPE_GENERAL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// General Configuration System
|
|
std::string p3GeneralConfig::getSetting(std::string opt)
|
|
{
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "p3GeneralConfig::getSetting(" << opt << ")";
|
|
std::cerr << std::endl;
|
|
#endif
|
|
RsStackMutex stack(cfgMtx); /***** LOCK STACK MUTEX ****/
|
|
|
|
/* extract from config */
|
|
std::map<std::string, std::string>::iterator it;
|
|
if (settings.end() == (it = settings.find(opt)))
|
|
{
|
|
std::string nullstring;
|
|
return nullstring;
|
|
}
|
|
return it->second;
|
|
}
|
|
|
|
void p3GeneralConfig::setSetting(std::string opt, std::string val)
|
|
{
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "p3GeneralConfig::setSetting(" << opt << " = " << val << ")";
|
|
std::cerr << std::endl;
|
|
#endif
|
|
{
|
|
RsStackMutex stack(cfgMtx); /***** LOCK STACK MUTEX ****/
|
|
|
|
/* extract from config */
|
|
std::map<std::string, std::string>::iterator it;
|
|
if (settings.end() != (it = settings.find(opt)))
|
|
{
|
|
if (it->second == val)
|
|
{
|
|
/* no change */
|
|
return;
|
|
}
|
|
}
|
|
|
|
settings[opt] = val;
|
|
}
|
|
/* outside mutex */
|
|
IndicateConfigChanged();
|
|
|
|
return;
|
|
}
|
|
|
|
RsSerialiser *p3GeneralConfig::setupSerialiser()
|
|
{
|
|
RsSerialiser *rss = new RsSerialiser();
|
|
rss->addSerialType(new RsGeneralConfigSerialiser());
|
|
return rss;
|
|
}
|
|
|
|
std::list<RsItem *> p3GeneralConfig::saveList(bool &cleanup)
|
|
{
|
|
RsStackMutex stack(cfgMtx); /***** LOCK STACK MUTEX ****/
|
|
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "p3GeneralConfig::saveList() KV sets: " << settings.size();
|
|
std::cerr << std::endl;
|
|
#endif
|
|
|
|
cleanup = true;
|
|
std::list<RsItem *> savelist;
|
|
|
|
RsConfigKeyValueSet *item = new RsConfigKeyValueSet();
|
|
std::map<std::string, std::string>::iterator it;
|
|
for(it = settings.begin(); it != settings.end(); it++)
|
|
{
|
|
RsTlvKeyValue kv;
|
|
kv.key = it->first;
|
|
kv.value = it->second;
|
|
item->tlvkvs.pairs.push_back(kv);
|
|
|
|
/* make sure we don't overload it */
|
|
if (item->tlvkvs.TlvSize() > 4000)
|
|
{
|
|
savelist.push_back(item);
|
|
item = new RsConfigKeyValueSet();
|
|
}
|
|
}
|
|
|
|
if (item->tlvkvs.pairs.size() > 0)
|
|
{
|
|
savelist.push_back(item);
|
|
}
|
|
|
|
return savelist;
|
|
}
|
|
|
|
|
|
bool p3GeneralConfig::loadList(std::list<RsItem *> load)
|
|
{
|
|
#ifdef CONFIG_DEBUG
|
|
std::cerr << "p3GeneralConfig::loadList() count: " << load.size();
|
|
std::cerr << std::endl;
|
|
#endif
|
|
|
|
RsStackMutex stack(cfgMtx); /***** LOCK STACK MUTEX ****/
|
|
|
|
/* add into settings */
|
|
RsConfigKeyValueSet *item = NULL;
|
|
std::list<RsItem *>::iterator it;
|
|
std::list<RsTlvKeyValue>::iterator kit;
|
|
|
|
for(it = load.begin(); it != load.end();)
|
|
{
|
|
item = dynamic_cast<RsConfigKeyValueSet *>(*it);
|
|
if (item)
|
|
{
|
|
for(kit = item->tlvkvs.pairs.begin();
|
|
kit != item->tlvkvs.pairs.end(); kit++)
|
|
{
|
|
settings[kit->key] = kit->value;
|
|
}
|
|
}
|
|
|
|
/* cleanup */
|
|
delete (*it);
|
|
it = load.erase(it);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/**** MUTEX NOTE:
|
|
* have protected all, but think that
|
|
* only the Indication and hash really need it
|
|
*/
|
|
|
|
pqiConfig::pqiConfig(uint32_t t)
|
|
:ConfInd(2), type(t)
|
|
{
|
|
return;
|
|
}
|
|
|
|
pqiConfig::~pqiConfig()
|
|
{
|
|
return;
|
|
}
|
|
|
|
uint32_t pqiConfig::Type()
|
|
{
|
|
RsStackMutex stack(cfgMtx); /***** LOCK STACK MUTEX ****/
|
|
return type;
|
|
}
|
|
|
|
std::string pqiConfig::Filename()
|
|
{
|
|
RsStackMutex stack(cfgMtx); /***** LOCK STACK MUTEX ****/
|
|
return filename;
|
|
}
|
|
|
|
std::string pqiConfig::Hash()
|
|
{
|
|
RsStackMutex stack(cfgMtx); /***** LOCK STACK MUTEX ****/
|
|
return hash;
|
|
}
|
|
|
|
void pqiConfig::IndicateConfigChanged()
|
|
{
|
|
RsStackMutex stack(cfgMtx); /***** LOCK STACK MUTEX ****/
|
|
ConfInd.IndicateChanged();
|
|
}
|
|
|
|
bool pqiConfig::HasConfigChanged(uint16_t idx)
|
|
{
|
|
RsStackMutex stack(cfgMtx); /***** LOCK STACK MUTEX ****/
|
|
return ConfInd.Changed(idx);
|
|
}
|
|
|
|
void pqiConfig::setFilename(std::string name)
|
|
{
|
|
RsStackMutex stack(cfgMtx); /***** LOCK STACK MUTEX ****/
|
|
filename = name;
|
|
}
|
|
|
|
void pqiConfig::setHash(std::string h)
|
|
{
|
|
RsStackMutex stack(cfgMtx); /***** LOCK STACK MUTEX ****/
|
|
hash = h;
|
|
}
|
|
|