Robustify accesses to server config
This commit is contained in:
parent
d36faa340a
commit
ac92e09262
14 changed files with 238 additions and 192 deletions
|
@ -61,43 +61,28 @@ void createAccount(std::string account){
|
|||
}
|
||||
|
||||
/// Status monitoring thread.
|
||||
/// Will check outputs, inputs and converters every five seconds
|
||||
/// Will check outputs, inputs and converters every three seconds
|
||||
void statusMonitor(void *np){
|
||||
IPC::semaphore configLock(SEM_CONF, O_CREAT | O_RDWR, ACCESSPERMS, 1);
|
||||
Controller::loadActiveConnectors();
|
||||
while (Controller::conf.is_active){
|
||||
// this scope prevents the configMutex from being locked constantly
|
||||
{
|
||||
tthread::lock_guard<tthread::mutex> guard(Controller::configMutex);
|
||||
bool changed = false;
|
||||
// checks online protocols, reports changes to status
|
||||
changed |= Controller::CheckProtocols(Controller::Storage["config"]["protocols"],
|
||||
Controller::capabilities);
|
||||
if (Controller::CheckProtocols(Controller::Storage["config"]["protocols"],
|
||||
Controller::capabilities)){
|
||||
Controller::writeProtocols();
|
||||
}
|
||||
// checks stream statuses, reports changes to status
|
||||
changed |= Controller::CheckAllStreams(Controller::Storage["streams"]);
|
||||
|
||||
// check if the config semaphore is stuck, by trying to lock it for 5 attempts of 1 second...
|
||||
if (!configLock.tryWaitOneSecond() && !configLock.tryWaitOneSecond() &&
|
||||
!configLock.tryWaitOneSecond() && !configLock.tryWaitOneSecond()){
|
||||
// that failed. We now unlock it, no matter what - and print a warning that it was stuck.
|
||||
WARN_MSG("Configuration semaphore was stuck. Force-unlocking it and re-writing config.");
|
||||
changed = true;
|
||||
}
|
||||
configLock.unlink();
|
||||
configLock.open(SEM_CONF, O_CREAT | O_RDWR, ACCESSPERMS, 1);
|
||||
if (changed || Controller::configChanged){
|
||||
Controller::writeConfig();
|
||||
Controller::configChanged = false;
|
||||
}
|
||||
Controller::CheckAllStreams(Controller::Storage["streams"]);
|
||||
}
|
||||
Util::sleep(5000); // wait at least 5 seconds
|
||||
Util::sleep(3000); // wait at least 3 seconds
|
||||
}
|
||||
if (Controller::restarting){
|
||||
Controller::prepareActiveConnectorsForReload();
|
||||
}else{
|
||||
Controller::prepareActiveConnectorsForShutdown();
|
||||
}
|
||||
configLock.unlink();
|
||||
}
|
||||
|
||||
static unsigned long mix(unsigned long a, unsigned long b, unsigned long c){
|
||||
|
@ -254,12 +239,9 @@ int main_loop(int argc, char **argv){
|
|||
Controller::conf.getOption("username", true)[0u] =
|
||||
Controller::Storage["config"]["controller"]["username"];
|
||||
}
|
||||
{
|
||||
IPC::semaphore configLock(SEM_CONF, O_CREAT | O_RDWR, ACCESSPERMS, 1);
|
||||
configLock.unlink();
|
||||
}
|
||||
Controller::writeConfig();
|
||||
Controller::checkAvailProtocols();
|
||||
Controller::writeCapabilities();
|
||||
createAccount(Controller::conf.getString("account"));
|
||||
Controller::conf.activate(); // activate early, so threads aren't killed.
|
||||
|
||||
|
|
|
@ -122,10 +122,6 @@ void Controller::SharedMemStats(void * config){
|
|||
statServer.parseEach(parseStatistics);
|
||||
if (firstRun){
|
||||
firstRun = false;
|
||||
servUpOtherBytes = 0;
|
||||
servDownOtherBytes = 0;
|
||||
servUpBytes = 0;
|
||||
servDownBytes = 0;
|
||||
for (std::map<std::string, struct streamTotals>::iterator it = streamStats.begin(); it != streamStats.end(); ++it){
|
||||
it->second.upBytes = 0;
|
||||
it->second.downBytes = 0;
|
||||
|
|
|
@ -211,43 +211,93 @@ namespace Controller {
|
|||
}
|
||||
}
|
||||
|
||||
/// Writes the current config to shared memory to be used in other processes
|
||||
void writeConfig(){
|
||||
static JSON::Value writeConf;
|
||||
bool changed = false;
|
||||
|
||||
void writeCapabilities(){
|
||||
std::string temp = capabilities.toPacked();
|
||||
static IPC::sharedPage mistCapaOut(SHM_CAPA, temp.size()+100, true, false);
|
||||
if (!mistCapaOut.mapped){
|
||||
FAIL_MSG("Could not open capabilities config for writing! Is shared memory enabled on your system?");
|
||||
return;
|
||||
}
|
||||
Util::RelAccX A(mistCapaOut.mapped, false);
|
||||
A.addField("dtsc_data", RAX_DTSC, temp.size());
|
||||
// write config
|
||||
memcpy(A.getPointer("dtsc_data"), temp.data(), temp.size());
|
||||
A.setRCount(1);
|
||||
A.setEndPos(1);
|
||||
A.setReady();
|
||||
}
|
||||
|
||||
void writeProtocols(){
|
||||
static JSON::Value proto_written;
|
||||
std::set<std::string> skip;
|
||||
skip.insert("online");
|
||||
skip.insert("error");
|
||||
if (!writeConf["config"].compareExcept(Storage["config"], skip)){
|
||||
writeConf["config"].assignFrom(Storage["config"], skip);
|
||||
VERYHIGH_MSG("Saving new config because of edit in server config structure");
|
||||
changed = true;
|
||||
}
|
||||
if (!writeConf["streams"].compareExcept(Storage["streams"], skip)){
|
||||
writeConf["streams"].assignFrom(Storage["streams"], skip);
|
||||
VERYHIGH_MSG("Saving new config because of edit in streams");
|
||||
changed = true;
|
||||
}
|
||||
if (writeConf["capabilities"] != capabilities){
|
||||
writeConf["capabilities"] = capabilities;
|
||||
VERYHIGH_MSG("Saving new config because of edit in capabilities");
|
||||
changed = true;
|
||||
}
|
||||
if (!changed){return;}//cancel further processing if no changes
|
||||
|
||||
static IPC::sharedPage mistConfOut(SHM_CONF, DEFAULT_CONF_PAGE_SIZE, true);
|
||||
if (!mistConfOut.mapped){
|
||||
FAIL_MSG("Could not open config shared memory storage for writing! Is shared memory enabled on your system?");
|
||||
if (Storage["config"]["protocols"].compareExcept(proto_written, skip)){return;}
|
||||
proto_written.assignFrom(Storage["config"]["protocols"], skip);
|
||||
std::string temp = proto_written.toPacked();
|
||||
static IPC::sharedPage mistProtoOut(SHM_PROTO, temp.size()+100, true, false);
|
||||
mistProtoOut.close();
|
||||
mistProtoOut.init(SHM_PROTO, temp.size()+100, true, false);
|
||||
if (!mistProtoOut.mapped){
|
||||
FAIL_MSG("Could not open protocol config for writing! Is shared memory enabled on your system?");
|
||||
return;
|
||||
}
|
||||
IPC::semaphore configLock(SEM_CONF, O_CREAT | O_RDWR, ACCESSPERMS, 1);
|
||||
//lock semaphore
|
||||
configLock.wait();
|
||||
//write config
|
||||
std::string temp = writeConf.toPacked();
|
||||
memcpy(mistConfOut.mapped, temp.data(), std::min(temp.size(), (size_t)mistConfOut.len));
|
||||
//unlock semaphore
|
||||
configLock.post();
|
||||
// write config
|
||||
{
|
||||
Util::RelAccX A(mistProtoOut.mapped, false);
|
||||
A.addField("dtsc_data", RAX_DTSC, temp.size());
|
||||
// write config
|
||||
memcpy(A.getPointer("dtsc_data"), temp.data(), temp.size());
|
||||
A.setRCount(1);
|
||||
A.setEndPos(1);
|
||||
A.setReady();
|
||||
}
|
||||
}
|
||||
|
||||
void writeStream(const std::string & sName, const JSON::Value & sConf){
|
||||
static std::map<std::string, JSON::Value> writtenStrms;
|
||||
static std::map<std::string, IPC::sharedPage> pages;
|
||||
static std::set<std::string> skip;
|
||||
if (!skip.size()){
|
||||
skip.insert("online");
|
||||
skip.insert("error");
|
||||
skip.insert("name");
|
||||
}
|
||||
if (sConf.isNull()){
|
||||
writtenStrms.erase(sName);
|
||||
pages.erase(sName);
|
||||
return;
|
||||
}
|
||||
if (!writtenStrms.count(sName) || !writtenStrms[sName].compareExcept(sConf, skip)){
|
||||
writtenStrms[sName].assignFrom(sConf, skip);
|
||||
IPC::sharedPage & P = pages[sName];
|
||||
std::string temp = writtenStrms[sName].toPacked();
|
||||
P.close();
|
||||
char tmpBuf[NAME_BUFFER_SIZE];
|
||||
snprintf(tmpBuf, NAME_BUFFER_SIZE, SHM_STREAM_CONF, sName.c_str());
|
||||
P.init(tmpBuf, temp.size()+100, true, false);
|
||||
if (!P){
|
||||
writtenStrms.erase(sName);
|
||||
pages.erase(sName);
|
||||
return;
|
||||
}
|
||||
Util::RelAccX A(P.mapped, false);
|
||||
A.addField("dtsc_data", RAX_DTSC, temp.size());
|
||||
// write config
|
||||
memcpy(A.getPointer("dtsc_data"), temp.data(), temp.size());
|
||||
A.setRCount(1);
|
||||
A.setEndPos(1);
|
||||
A.setReady();
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes the current config to shared memory to be used in other processes
|
||||
void writeConfig(){
|
||||
writeProtocols();
|
||||
jsonForEach(Storage["streams"], it){
|
||||
writeStream(it.key(), *it);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -32,5 +32,8 @@ namespace Controller {
|
|||
void initState();
|
||||
void deinitState(bool leaveBehind);
|
||||
void writeConfig();
|
||||
void writeStream(const std::string & sName, const JSON::Value & sConf);
|
||||
void writeCapabilities();
|
||||
void writeProtocols();
|
||||
|
||||
}
|
||||
|
|
|
@ -148,6 +148,7 @@ namespace Controller {
|
|||
out[jit.key()]["name"] = jit.key();
|
||||
Log("STRM", std::string("New stream ") + jit.key());
|
||||
}
|
||||
Controller::writeStream(jit.key(), out[jit.key()]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -240,6 +241,7 @@ namespace Controller {
|
|||
}
|
||||
Log("STRM", std::string("Deleted stream ") + name);
|
||||
out.removeMember(name);
|
||||
Controller::writeStream(name, JSON::Value());//Null JSON value = delete
|
||||
}
|
||||
|
||||
} //Controller namespace
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue