From 7450a788baa5d9d7ea16dcf1468adac424dd6305 Mon Sep 17 00:00:00 2001 From: Chris Tallon Date: Wed, 7 Mar 2018 20:15:47 +0000 Subject: [PATCH] Switch to libconfig++ --- Makefile | 7 +- config.c | 524 ----------------------------------------- config.h | 80 ------- jsonserver.c | 101 +++----- jsonserver.conf.sample | 9 +- 5 files changed, 47 insertions(+), 674 deletions(-) delete mode 100644 config.c delete mode 100644 config.h diff --git a/Makefile b/Makefile index f9fa715..46a3cd4 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,6 @@ +# Dependencies: +# libjsoncpp-dev libconfig++-dev + # # Makefile for a Video Disk Recorder plugin # @@ -56,7 +59,7 @@ CXXFLAGS += -fpermissive ### The object files (add further files here): -OBJS = $(PLUGIN).o mongoose.o handler.o log.o config.o +OBJS = $(PLUGIN).o mongoose.o handler.o log.o ### The main target: @@ -105,7 +108,7 @@ install-i18n: $(I18Nmsgs) ### Targets: $(SOFILE): $(OBJS) - $(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) -ljsoncpp -o $@ + $(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) -ljsoncpp -lconfig++ -o $@ install-lib: $(SOFILE) install -D $^ $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION) diff --git a/config.c b/config.c deleted file mode 100644 index 3866abc..0000000 --- a/config.c +++ /dev/null @@ -1,524 +0,0 @@ -/* - Copyright 2004-2005 Chris Tallon - Copyright 2004-2005 University Of Bradford - - This file is part of VOMP. - - VOMP is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - VOMP 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with VOMP; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include "config.h" - -Config::Config() -{ - initted = 0; - lastLineLength = 0; - log = Log::getInstance(); -} - -int Config::init(char* takeFileName) -{ - if (initted) return 1; - - pthread_mutex_init(&fileLock, NULL); - - if (strlen(takeFileName) > (MAX_FILENAME_LENGTH - 1)) - { - log->log("Config", Log::DEBUG, "Config error: Config filename too long"); - return 0; - } - - strcpy(fileName, takeFileName); - strcpy(fileNameTemp, takeFileName); - strcat(fileNameTemp, ".tmp"); - - file = fopen(fileName, "r"); - if (!file) - { - file = fopen(fileName, "w"); - if (!file) - { - log->log("Config", Log::DEBUG, "Config error: Could not access config file"); - return 0; - } - } - fclose(file); - - initted = 1; - log->log("Config", Log::DEBUG, "Opened config file: %s", fileName); - - return 1; -} - -int Config::status() -{ - return initted; -} - -int Config::shutdown() -{ - if (!initted) return 1; - - pthread_mutex_lock(&fileLock); - initted = 0; - pthread_mutex_unlock(&fileLock); - pthread_mutex_destroy(&fileLock); - - return 1; -} - -int Config::openFile() -{ - if (!initted) return 0; - if (pthread_mutex_lock(&fileLock)) - { - log->log("Config", Log::DEBUG, "Config error: Could not get lock"); - return 0; - } - if (!initted) - { - log->log("Config", Log::DEBUG, "Config error: Initted 0 after lock"); - pthread_mutex_unlock(&fileLock); - return 0; - } - - file = fopen(fileName, "r"); - if (!file) - { - log->log("Config", Log::DEBUG, "Config error: Could not open config file"); - pthread_mutex_unlock(&fileLock); - return 0; - } - return 1; -} - -void Config::closeFile() -{ - if (!initted) return; - - fclose(file); - file = NULL; - pthread_mutex_unlock(&fileLock); -} - -int Config::readLine() -{ - if (!initted || !file) { log->log("Config", Log::DEBUG, "1"); return 0; } - if (!fgets(buffer, BUFFER_LENGTH-1, file)) { /*log->log("Config", Log::DEBUG, "2");*/ return 0; } - lastLineLength = strlen(buffer); -// log->log("Config", Log::DEBUG, "buffer before trim: '%s'", buffer); - trim(buffer); -// log->log("Config", Log::DEBUG, "buffer after trim: '%s'", buffer); - return 1; -} - -// START HERE - -FILE* Config::copyToHere(long position) -{ - FILE* newFile = fopen(fileNameTemp, "w"); - - if (!newFile) return NULL; - - long newPos = 0; - rewind(file); - - while (newPos < position) - { - fgets(buffer, BUFFER_LENGTH-1, file); - fputs(buffer, newFile); - newPos += strlen(buffer); - } - return newFile; -} - -int Config::copyRest(FILE* newFile) -{ - if (newFile) - { - while(fgets(buffer, BUFFER_LENGTH-1, file)) - { - fputs(buffer, newFile); - } - - fclose(newFile); - } - fclose(file); - file = NULL; - - if (newFile) rename(fileNameTemp, fileName); - - pthread_mutex_unlock(&fileLock); - return 1; -} - -int Config::deleteValue(const char* section, char* key) -{ - if (!initted) return 0; - if (!openFile()) return 0; - - if (!findSection(section)) - { - closeFile(); - log->log("Config", Log::DEBUG, "Config error: Section %s not found", section); - return 0; - } - if (!findKey(key)) - { - closeFile(); - log->log("Config", Log::DEBUG, "Config error: Key %s not found", key); - return 0; - } - - FILE* newFile = copyToHere(ftell(file) - lastLineLength); - fgets(buffer, BUFFER_LENGTH-1, file); - - return copyRest(newFile); -} - -int Config::setValueLong(const char* section, char* key, long newValue) -{ - char longBuffer[50]; - sprintf(longBuffer, "%li", newValue); - return setValueString(section, key, longBuffer); -} - -int Config::setValueLongLong(char* section, char* key, long long newValue) -{ - char longBuffer[50]; - sprintf(longBuffer, "%lli", newValue); - return setValueString(section, key, longBuffer); -} - -int Config::setValueDouble(char* section, char* key, double newValue) -{ - char doubleBuffer[50]; - sprintf(doubleBuffer, "%f", newValue); - return setValueString(section, key, doubleBuffer); -} - -int Config::setValueString(const char* section, const char* key, const char* newValue) -{ - if (!initted) return 0; - if (!openFile()) return 0; - - if (findSection(section)) - { - if (findKey(key)) - { - FILE* newFile = copyToHere(ftell(file) - lastLineLength); - if (!newFile) - { - closeFile(); - log->log("Config", Log::DEBUG, "Config error: Could not write temp config file"); - return 0; - } - - fgets(buffer, BUFFER_LENGTH-1, file); - fprintf(newFile, "%s = %s\n", key, newValue); - return copyRest(newFile); - } - else - { - rewind(file); - findSection(section); - FILE* newFile = copyToHere(ftell(file)); - if (!newFile) - { - closeFile(); - log->log("Config", Log::DEBUG, "Config error: Could not write temp config file"); - return 0; - } - - fprintf(newFile, "%s = %s\n", key, newValue); - return copyRest(newFile); - } - } - else - { - // section not found - fseek(file, 0, SEEK_END); - FILE* newFile = copyToHere(ftell(file)); - if (!newFile) - { - closeFile(); - log->log("Config", Log::DEBUG, "Config error: Could not write temp config file"); - return 0; - } - - fprintf(newFile, "[%s]\n%s = %s\n", section, key, newValue); - return copyRest(newFile); - } -} - -char* Config::getSectionKeyNames(const char* section, int& numberOfReturns, int& allKeysSize) -{ - numberOfReturns = 0; - allKeysSize = 0; - char* allKeys = NULL; - int allKeysIndex = 0; - int keyLength; - char* equalspos; - - if (!initted) return NULL; - if (!openFile()) return NULL; - if (!findSection(section)) return NULL; - - char foundKey[BUFFER_LENGTH]; - - while(readLine()) - { - // Is this line a section header? if so, exit - if ((buffer[0] == '[') && (buffer[strlen(buffer)-1] == ']')) break; - - equalspos = strstr(buffer, "="); - if (!equalspos) continue; // if there is no = then it's not a key - memcpy(foundKey, buffer, equalspos-buffer); - foundKey[equalspos-buffer] = '\0'; - trim(foundKey); - keyLength = strlen(foundKey); - allKeysSize += keyLength + 1; - allKeys = (char*)realloc(allKeys, allKeysSize); - memcpy(&allKeys[allKeysIndex], foundKey, keyLength); - allKeysIndex += keyLength; - allKeys[allKeysIndex] = '\0'; - allKeysIndex++; - numberOfReturns++; - } - - closeFile(); - return allKeys; -} - - -// END HERE - -int Config::findSection(const char* section) -{ - if (!initted || !file) return 0; - if (strlen(section) > (BUFFER_LENGTH-2)) - { - log->log("Config", Log::DEBUG, "Config error: Section given exceeds max length"); - return 0; - } - - char toFind[BUFFER_LENGTH]; - toFind[0] = '['; - toFind[1] = '\0'; - strcat(toFind, section); - strcat(toFind, "]"); - - while(readLine()) - { -// log->log("Config", Log::DEBUG, "to find '%s' this line '%s'", toFind, buffer); - if (!strcmp(toFind, buffer)) return 1; - } - return 0; -} - -int Config::findKey(const char* key) -{ - if (!initted || !file) return 0; - - if (strlen(key) > (BUFFER_LENGTH-1)) - { - log->log("Config", Log::DEBUG, "Config error: Key given exceeds max length"); - return 0; - } - - char prepForTest[BUFFER_LENGTH]; - - // do a rough search first, this could match substrings that we don't want - while(readLine()) - { - // Is this line a section header? if so, exit - if ((buffer[0] == '[') && (buffer[strlen(buffer)-1] == ']')) return 0; - if (strstr(buffer, key)) - { - // rough search found match - char* equalspos = strstr(buffer, "="); - if (!equalspos) continue; - memcpy(prepForTest, buffer, equalspos-buffer); - prepForTest[equalspos-buffer] = '\0'; - trim(prepForTest); - - if (!strcmp(key, prepForTest)) - { - // in buffer, set all up to equals to space, then trim! - for(char* curPos = buffer; curPos <= equalspos; curPos++) - { - *curPos = ' '; - } - trim(buffer); - return 1; - } - } - } - return 0; -} - -char* Config::getValueString(const char* section, const char* key) -{ - if (!initted) return NULL; - if (!openFile()) return NULL; - - if (!findSection(section)) - { - closeFile(); - log->log("Config", Log::DEBUG, "Config error: Section %s not found", section); - return 0; - } - if (!findKey(key)) - { - closeFile(); - log->log("Config", Log::DEBUG, "Config error: Key %s not found", key); - return 0; - } - - char* returnString = new char[strlen(buffer)+1]; - strcpy(returnString, buffer); - - closeFile(); - - return returnString; -} - -long Config::getValueLong(const char* section, const char* key, int* failure) -{ - *failure = 1; - if (!initted) return 0; - if (!openFile()) return 0; - - if (!findSection(section)) - { - closeFile(); - log->log("Config", Log::DEBUG, "Config error: Section %s not found", section); - return 0; - } - if (!findKey(key)) - { - closeFile(); - log->log("Config", Log::DEBUG, "Config error: Key %s not found", key); - return 0; - } - *failure = 0; - - char* check; - long retVal = strtol(buffer, &check, 10); - if ((retVal == 0) && (check == buffer)) *failure = 1; - closeFile(); - - return retVal; -} - -long long Config::getValueLongLong(char* section, char* key, int* failure) -{ - *failure = 1; - if (!initted) return 0; - if (!openFile()) return 0; - - if (!findSection(section)) - { - closeFile(); - log->log("Config", Log::DEBUG, "Config error: Section %s not found", section); - return 0; - } - if (!findKey(key)) - { - closeFile(); - log->log("Config", Log::DEBUG, "Config error: Key %s not found", key); - return 0; - } - *failure = 0; - - char* check; - long long retVal = strtoll(buffer, &check, 10); - if ((retVal == 0) && (check == buffer)) *failure = 1; - closeFile(); - - return retVal; -} - -double Config::getValueDouble(char* section, char* key, int* failure) -{ - *failure = 1; - if (!initted) return 0; - if (!openFile()) return 0; - - if (!findSection(section)) - { - closeFile(); - log->log("Config", Log::DEBUG, "Config error: Section %s not found", section); - return 0; - } - if (!findKey(key)) - { - closeFile(); - log->log("Config", Log::DEBUG, "Config error: Key %s not found", key); - return 0; - } - - *failure = 0; - - char* check; - double retVal = strtod(buffer, &check); - if ((retVal == 0) && (check == buffer)) *failure = 1; - - closeFile(); - - return retVal; -} - - - -void Config::trim(char* str) -{ - int pos, len, start, end; - - // Kill comments - len = strlen(str); - for(pos = 0; pos < len; pos++) - { - if ((str[pos] == '#') || (str[pos] == ';')) - { - // Mod. If #/; is at start of line ok. Else, if it is after a space, ok. - - if ((pos == 0) || (isspace(str[pos - 1]))) - { - str[pos] = '\0'; - break; - } - - } - } - - len = strlen(str); - end = len; - if (!len) return; - - start = 0; - while(isspace(str[start])) start++; - while(isspace(str[end-1])) - { - end--; - if (end == 0) - { - str[0] = '\0'; - return; - } - } - for(pos = start; pos < end; pos++) str[pos - start] = str[pos]; - str[end - start] = '\0'; -} diff --git a/config.h b/config.h deleted file mode 100644 index 2e4a2dd..0000000 --- a/config.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - Copyright 2004-2005 Chris Tallon - Copyright 2004-2005 University Of Bradford - - This file is part of VOMP. - - VOMP is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - VOMP 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with VOMP; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#ifndef CONFIG_H -#define CONFIG_H - -#include -#include -#include -#include -#include - -#include "log.h" - -#define MAX_FILENAME_LENGTH 500 -#define BUFFER_LENGTH 1500 - -class Config -{ - public: - Config(); - - int init(char* fileName); - int shutdown(); - int status(); - - char* getValueString(const char* section, const char* key); - long getValueLong(const char* section, const char* key, int* failure); - long long getValueLongLong(char* section, char* key, int* failure); - double getValueDouble(char* section, char* key, int* failure); - - int setValueString(const char* section, const char* key, const char* newValue); - int setValueLong(const char* section, char* key, long newValue); - int setValueLongLong(char* section, char* key, long long newValue); - int setValueDouble(char* section, char* key, double newValue); - - int deleteValue(const char* section, char* key); // err.. delete "key". - char* getSectionKeyNames(const char* section, int& numberOfReturns, int& length); - - private: - pthread_mutex_t fileLock; - int initted; - int lastLineLength; - Log* log; - - char fileName[MAX_FILENAME_LENGTH]; - char fileNameTemp[MAX_FILENAME_LENGTH]; - - FILE* file; - char buffer[BUFFER_LENGTH]; - - int openFile(); - void closeFile(); - int readLine(); - int findSection(const char* section); - int findKey(const char* key); - void trim(char* sting); - FILE* copyToHere(long position); - int copyRest(FILE* newFile); -}; - -#endif diff --git a/jsonserver.c b/jsonserver.c index 8d1cbb8..fa4ea8c 100644 --- a/jsonserver.c +++ b/jsonserver.c @@ -8,10 +8,12 @@ #include #include +// Config docs: http://www.hyperrealm.com/libconfig/libconfig_manual.html#The-C_002b_002b-API +#include + #include "mongoose.h" #include "handler.h" #include "log.h" -#include "config.h" static const char *VERSION = "0.0.1"; static const char *DESCRIPTION = "JSON data server plugin for VDR"; @@ -22,10 +24,7 @@ private: // Add any member variables or functions you may need here. struct mg_context *mg; Log* log; - Config* config; - char* cfgDocRoot; - char* cfgPort; - char* cfgSSLFilename; + libconfig::Config config; bool mgRunning; public: cPluginJsonserver(void); @@ -56,11 +55,7 @@ cPluginJsonserver::cPluginJsonserver(void) // DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL // VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT! - config = NULL; log = NULL; - cfgDocRoot = NULL; - cfgPort = NULL; - cfgSSLFilename = NULL; mgRunning = false; } @@ -69,9 +64,6 @@ cPluginJsonserver::~cPluginJsonserver() // Clean up after yourself! if (log) delete log; log = NULL; - - if (config) delete config; - config = NULL; } const char *cPluginJsonserver::CommandLineHelp(void) @@ -101,87 +93,73 @@ bool cPluginJsonserver::Start(void) dsyslog("jsonserver: Error: Could not get config dir from VDR"); return false; } - char* configFile; - if (asprintf(&configFile, "%s/jsonserver.conf", configDir) == -1) + + std::string configFile(std::string(configDir) + std::string("/server.conf")); + dsyslog("%s", configFile.c_str()); + try { - dsyslog("jsonserver: Error: asprintf"); - return false; + config.readFile(configFile.c_str()); } - - dsyslog("%s", configFile); - - log = new Log(); - - config = new Config(); - if (config->init(configFile)) + catch (const libconfig::FileIOException &fioex) { - dsyslog("jsonserver: Config file found"); - free(configFile); + dsyslog("jsonserver: Failed to read config file"); + return false; } - else + catch(const libconfig::ParseException &pex) { - dsyslog("jsonserver: Error: Config file not found"); - free(configFile); - delete config; - config = NULL; + dsyslog("jsonserver: Config parse error at %s: %i - %s", pex.getFile(), pex.getLine(), pex.getError()); return false; } - char* cfgLogFilename = config->getValueString("General", "Log file"); - if (cfgLogFilename) + std::string cfgLogFilename; + if (config.lookupValue("log-file", cfgLogFilename)) { - log->init(Log::DEBUG, cfgLogFilename); - delete[] cfgLogFilename; + log = new Log(); + log->init(Log::DEBUG, cfgLogFilename.c_str()); log->log("Main", Log::INFO, "Logging started"); } else { dsyslog("jsonserver: Logging disabled"); } - - cfgDocRoot = config->getValueString("General", "JS App Dir"); - if (!cfgDocRoot) + + std::string cfgDocRoot; + if (!config.lookupValue("doc-root", cfgDocRoot)) { - log->log("Main", Log::CRIT, "Config General/JS App Dir not found"); - dsyslog("jsonserver: Error: Could not load JS App Dir from plugin config file"); + log->log("Main", Log::CRIT, "Failed to load doc-root from config"); + dsyslog("jsonserver: Could not load JS App Dir from plugin config file"); delete log; - delete config; log = NULL; - config = NULL; return false; } - cfgPort = config->getValueString("General", "Port number"); - if (!cfgPort) + std::string cfgPort; + if (!config.lookupValue("http-port", cfgPort)) { - cfgPort = new char[5]; - strcpy(cfgPort, "8005"); + log->log("Main", Log::CRIT, "Failed to load http-port from config"); + dsyslog("jsonserver: Could not load http-port from plugin config file"); + delete log; + log = NULL; + return false; } - char* cfgSSLFilename = config->getValueString("General", "SSL PEM File"); - if (!cfgSSLFilename) + std::string cfgSSLFilename; + if (!config.lookupValue("ssl-pem-file", cfgSSLFilename)) { - log->log("Main", Log::ALERT, "Config General / SSL PEM File not found - can't run!"); - dsyslog("jsonserver: ERROR: Config: SSL PEM not found"); + log->log("Main", Log::CRIT, "Failed to load ssl-pem-file from config"); + dsyslog("jsonserver: Could not load ssl-pem-file from plugin config file"); delete log; - delete config; log = NULL; - config = NULL; return false; } - + // Make Mongoose options const char *options[] = { - "document_root", cfgDocRoot, -// "listening_ports", cfgPort, + "document_root", cfgDocRoot.c_str(), + "listening_ports", cfgPort.c_str(), "num_threads", "5", - - "listening_ports", "8005s", - "ssl_certificate", cfgSSLFilename, - -// "auth_domain", "VDRWeb", - + "ssl_certificate", cfgSSLFilename.c_str(), NULL }; @@ -201,9 +179,6 @@ void cPluginJsonserver::Stop(void) // Stop any background activities the plugin is performing. if (mgRunning) mg_stop(mg); mgRunning = false; - if (cfgDocRoot) { delete[] cfgDocRoot; cfgDocRoot = NULL; } - if (cfgPort) { delete[] cfgPort; cfgPort = NULL; } - if (cfgSSLFilename) { delete[] cfgSSLFilename; cfgSSLFilename = NULL; } } void cPluginJsonserver::Housekeeping(void) diff --git a/jsonserver.conf.sample b/jsonserver.conf.sample index 4fdc122..fa95733 100644 --- a/jsonserver.conf.sample +++ b/jsonserver.conf.sample @@ -1,5 +1,4 @@ -[General] -Log file = /var/log/jsonserver.log -JS App Dir = /srv/vdrweb -Port number = 8005 - +log-file = "/home/chris/dvb/vdrweb/jsonserver.log"; +doc-root = "/home/chris/dvb/vdrweb/html"; +ssl-pem-file = "/home/chris/dvb/vdrweb/sslcert.pem"; +http-port = "8005"; -- 2.39.2