Changeset 229 for Evidence


Ignore:
Timestamp:
06/24/10 07:51:15 (15 years ago)
Author:
ogrimm
Message:
Config requests non-blocking if not made from main thread, adapted all servers to GetConfig() returning std::string, workaround for erroneous SERVICE_LIST
Location:
Evidence
Files:
1 added
10 edited

Legend:

Unmodified
Added
Removed
  • Evidence/Alarm.cc

    r227 r229  
    8080
    8181  // Get DIM servers to observe
    82   char *Token = strtok(GetConfig("servers"), " \t");
    83   int Pos;
    84   while (Token != NULL) {
     82  vector<string> Token = Tokenize(GetConfig("servers"));
     83
     84  for (int i=0; i<Token.size(); i++) {
    8585        // Extract server name and email
    86         N.Server = Token;
    87         Pos = N.Server.find(':');
    88         if (Pos > 0 && Pos < N.Server.size()-2) {
    89           N.Email = N.Server.substr(Pos+1, string::npos);
    90           N.Server = N.Server.substr(0, Pos);   
    91         }
     86        vector<string> A = Tokenize(Token[i], ":");
     87        N.Server = A[0];
     88        if (A.size() == 2) N.Email = A[1];
    9289        else N.Email = string();
    9390
     
    10299
    103100        List.push_back(N);
    104     Token = strtok(NULL, " \t");     
    105101  }
    106102
     
    247243   
    248244    Alarm.UpdateAlarmSummary();
    249     sleep(atoi(Alarm.GetConfig("period")));
    250   }
    251 }
     245    sleep(atoi(Alarm.GetConfig("period").c_str()));
     246  }
     247}
  • Evidence/Bridge.cc

    r224 r229  
    2424using namespace std;
    2525
    26 
    2726// Class declaration
    2827class Bridge: public DimClient, public EvidenceServer {
    2928
    3029        struct Item {
    31           string Name;
    3230          DimCommand *Command;
    3331          DimStampedInfo *DataItem;
     
    3533          char *Data;
    3634        };
    37         vector<struct Item> List;
     35        map<string, struct Item> Map;
    3836
    3937        DimInfo *ServerList;
     
    4139    void infoHandler();
    4240    void commandHandler();
     41        public:
    4342        void AddService(string, char *, int);
    4443        void RemoveService(string);
    45    
     44        void BugFix();
     45
    4646  public:
    4747    Bridge(char *, int);
     
    6363Bridge::~Bridge() {
    6464
    65   while (List.size() != 0) RemoveService(List[0].Name); 
     65  while (Map.size() != 0) RemoveService((*Map.begin()).first); 
    6666  delete ServerList;
    6767}
     
    7777
    7878  // If service is DIS_DNS/SERVER_LIST, subscribe to all SERVICE_LIST services
    79   if (strcmp(I->getName(), "DIS_DNS/SERVER_LIST") == 0) {       
     79  if (strcmp(I->getName(), "DIS_DNS/SERVER_LIST") == 0) {
     80    printf("DIS_DNS/SERVER_LIST: '%s'\n", I->getString());
    8081        char *Token = strtok(I->getString(), "+-!@");   
    8182        while (Token != NULL) {
     
    9495  // If service is SERVICE_LIST, scan and subscribe/unsubscribe to services
    9596  if (strstr(I->getName(), "/SERVICE_LIST") != NULL) {
     97
     98        // Bug fix for empty SERVICE_LIST
     99        if (strlen(I->getString()) == 0) {
     100          string Tmp(I->getName());
     101          RemoveService(I->getName());
     102          AddService(Tmp.c_str(), (char *) "C", DimSERVICE);
     103          return;
     104        }
     105
    96106        char *Format, *Name = strtok(I->getString(), "+-!|");
    97107        while (Name != NULL) {
     
    131141  }
    132142
    133   // Identify service and repeat to secondary DNS
    134   for (int Service=0; Service<List.size(); Service++) if (I == List[Service].DataItem) {
    135 
    136     // Copy service data
    137     delete[] List[Service].Data;
    138     List[Service].Data = new char [I->getSize()];
    139     memcpy(List[Service].Data, I->getData(), I->getSize());
    140 
    141         // Set new service properties and update service
    142     List[Service].Service->setQuality(I->getQuality());
    143     List[Service].Service->setTimestamp(I->getTimestamp(), I->getTimestampMillisecs());
    144         List[Service].Service->updateService(List[Service].Data, I->getSize());
    145   }
     143  // Check if service known and repeat to secondary DNS
     144  if (Map.count(I->getName()) == 0) return;
     145
     146  // Copy service data
     147  delete[] Map[I->getName()].Data;
     148  Map[I->getName()].Data = new char [I->getSize()];
     149  memcpy(Map[I->getName()].Data, I->getData(), I->getSize());
     150
     151  // Set new service properties and update service
     152  Map[I->getName()].Service->setQuality(I->getQuality());
     153  Map[I->getName()].Service->setTimestamp(I->getTimestamp(), I->getTimestampMillisecs());       
     154  Map[I->getName()].Service->updateService(Map[I->getName()].Data, I->getSize());
    146155}
    147156
     
    161170
    162171  // Check if already subscribed to this service
    163   for (int i=0; i<List.size(); i++) {
    164         if (Name == List[i].Name) return;
    165   }
     172  if (Map.count(Name) != 0) return;
    166173
    167174  // Create subscription and service to secondary DNS or new command
    168   struct Item New = {Name, NULL, NULL, NULL, NULL};
    169 
     175  Map[Name].Command = NULL;
     176  Map[Name].DataItem = NULL;
     177  Map[Name].Service = NULL;
     178  Map[Name].Data = NULL;
     179 
    170180  if  (Type == DimSERVICE) { 
    171         New.Service = new DimService(Name.c_str(), (char *) Format, New.Data, 0);
    172         New.DataItem = new DimStampedInfo(Name.c_str(), NO_LINK, this);
    173   }
    174   else if (Type == DimCOMMAND) New.Command = new DimCommand(Name.c_str(), Format, this);
    175 
    176   List.push_back(New);
     181        Map[Name].Service = new DimService(Name.c_str(), (char *) Format, Map[Name].Data, 0);
     182        Map[Name].DataItem = new DimStampedInfo(Name.c_str(), NO_LINK, this);
     183  }
     184  else if (Type == DimCOMMAND) Map[Name].Command = new DimCommand(Name.c_str(), Format, this);
    177185}
    178186
     
    181189void Bridge::RemoveService(string Name) {
    182190
    183   vector<struct Item>::iterator E;
    184   for (E=List.begin(); E<List.end(); ++E) if (Name == (*E).Name) {
    185         delete (*E).DataItem;
    186         delete (*E).Service;
    187         delete[] (*E).Data;
    188         delete (*E).Command;
    189 
    190         List.erase(E);
    191   }
     191  // Check if actually subscribed to service 
     192  if (Map.count(Name) == 0) return;
     193
     194  delete Map[Name].DataItem;
     195  delete Map[Name].Service;
     196  delete[] Map[Name].Data;
     197  delete Map[Name].Command;
     198
     199  Map.erase(Name);
    192200}
    193201
     
    206214 
    207215  // Sleep until signal caught
    208   pause();
    209 }
     216  while (!Class.ExitRequest) pause();
     217}
  • Evidence/Config.cc

    r224 r229  
    6767  FileContent = NULL;
    6868
     69  // Signaling interferes with inotify() mechnism
     70  signal(SIGUSR2, SIG_IGN);
     71 
    6972  // Initialise mutex (errno is not set by pthread_mutex_init())
    7073  if (pthread_mutex_init(&Mutex, NULL) != 0) {
     
    266269          Notify = -1;
    267270  }
    268  
     271
    269272  // Sleep until file changes or signal caught
    270273  while (!Config.ExitRequest) {
    271274    if (Notify != -1) {
    272           read(Notify, &Event, sizeof(Event));
    273           Config.ConfigChanged();
     275          if (read(Notify, &Event, sizeof(Event)) == sizeof(Event)) Config.ConfigChanged();
    274276        }
    275277    else pause();         
  • Evidence/DColl.cc

    r224 r229  
    1919#include <string>
    2020#include <sstream>
     21#include <iostream>
    2122#include <vector>
    2223#include <sys/stat.h>
     
    4445        float DataSizeMB, LogSizeMB;
    4546        int DataSizeLastUpdate, LogSizeLastUpdate;
    46         char *BaseDir;
    4747    DimService *LogSizeService, *DataSizeService, *DataFilename;
    48         int SizeUpdateDelay;
    4948        int TimeForNextFile;
    50         int RollOver;
    5149
    5250        vector<regex_t> RegEx;
    53        
     51
    5452    void infoHandler();
    5553    void commandHandler();
     
    5755        void RemoveService(string);
    5856        off_t FileSize(FILE *);
    59    
     57    void ConfigChanged();
     58
    6059  public:
    6160    DataHandler();
     
    6362};
    6463
     64void DataHandler::ConfigChanged() {
     65  //printf("Handler called in PID %u\n", pthread_self());
     66}
     67
    6568//
    6669// Constructor
     
    8083  TimeForNextFile = 0;
    8184
    82   // Request configuration data
    83   BaseDir = GetConfig("basedir");
    84   SizeUpdateDelay = atoi(GetConfig("sizeupdate"));
    85   RollOver = atoi(GetConfig("rollover"));
     85  // Request configuration data / initialise for later non-blocking updates
     86  GetConfig("basedir");
     87  GetConfig("sizeupdate");
     88  GetConfig("rollover");
    8689
    8790  // Open log file
    88   if ((LogFile = fopen((string(BaseDir)+"/"+LOG_FILENAME).c_str(), "a")) == NULL) {
     91  if ((LogFile = fopen((GetConfig("basedir")+"/"+LOG_FILENAME).c_str(), "a")) == NULL) {
    8992    Message(FATAL, "Could not open log file (%s)", strerror(errno));
    9093  }
    91               
     94             
    9295  // Create services for file sizes and data file name
    9396  DataSizeMB = 0;
     
    100103
    101104  // Compile regular expressions
    102   char *Exclude = GetConfig("exclude");
    103   char *Token = strtok(Exclude, "\t ");
    104105  regex_t R;
    105 
    106   while (Token != NULL) {
    107         int Ret = regcomp(&R, Token, REG_EXTENDED|REG_NOSUB);
     106  vector<string> Exclude = Tokenize(GetConfig("exclude"), " \t");
     107  for (int i=0; i<Exclude.size(); i++) {
     108        printf("'%s'\n",Exclude[i].c_str());
     109
     110        int Ret = regcomp(&R, Exclude[i].c_str(), REG_EXTENDED|REG_NOSUB);
    108111        if (Ret != 0) {
    109112          char Err[200];
    110113          regerror(Ret, &R, Err, sizeof(Err));
    111           Message(ERROR, "Error compiling regular expression '%s' (%s)", Token, Err);
     114          Message(ERROR, "Error compiling regular expression '%s' (%s)", Exclude[i].c_str(), Err);
    112115        }
    113116        else RegEx.push_back(R);
    114 
    115         Token = strtok(NULL, "\t ");
    116   }
    117  
     117  }
     118
    118119  // Provide logging command   
    119120  LogCommand = new DimCommand("DColl/Log", (char *) "C", this);
     
    158159void DataHandler::infoHandler() {
    159160
     161  // Check if service available
    160162  DimInfo *I = getInfo();
    161 
    162   // Check if service available
    163163  if (!ServiceOK(I)) return;
    164164
     
    166166  // ====== Part A: Handle service subscriptions ===
    167167  //
    168   // Services are added here, removal only in constructor.
     168  // Services are added here, removal only in destructor.
    169169 
    170170  // If service is DIS_DNS/SERVER_LIST, subscribe to all SERVICE_LIST services
     
    182182  // Subscribe to all services (but not to commands and RPCs)
    183183  if (strstr(I->getName(), "/SERVICE_LIST") != NULL) {
     184
     185        // Bug fix for empty SERVICE_LIST
     186        if (strlen(I->getString()) == 0) {
     187          string Tmp(I->getName());
     188          RemoveService(I->getName());
     189          AddService(Tmp.c_str());
     190          return;
     191        }
     192
    184193        char *Name = strtok(I->getString(), "+-!|");
    185194        while (Name != NULL) {
     
    211220
    212221        // Get time structure with date rollover
    213         if (T->tm_hour >= RollOver) T->tm_mday++;
     222        if (T->tm_hour >= atoi(GetConfig("rollover").c_str())) T->tm_mday++;
    214223        if (mktime(T) == -1) Message(ERROR, "mktime() failed, check filename");
    215224
    216225        // Create direcory if not existing (ignore error if already existing)
    217226        char *Dir;
    218         if (asprintf(&Dir, "%s/%d", BaseDir, T->tm_year+1900) == -1) {
     227        if (asprintf(&Dir, "%s/%d", GetConfig("basedir").c_str(), T->tm_year+1900) == -1) {
    219228          Message(FATAL, "asprintf() failed, could not create direcory name"); 
    220229        }
     
    240249        T->tm_sec = 0;
    241250        T->tm_min = 0;
    242         T->tm_hour = RollOver;
     251        T->tm_hour = atoi(GetConfig("rollover").c_str());
    243252        TimeForNextFile = mktime(T);
    244253  }
     
    261270
    262271        // Translate data into ASCII
    263         char *Text = EvidenceServer::ToString(I);
    264 
    265         if (Text != NULL) {
     272        string Text = EvidenceServer::ToString(I);
     273
     274        if (!Text.empty()) {
    266275          // Replace new line by '\' and all other control characters by white space
    267           for (int i=0; i<strlen(Text); i++) {
     276          for (int i=0; i<Text.size(); i++) {
    268277                if (Text[i] == '\n') Text[i] = '\\';
    269278                else if (iscntrl(Text[i])) Text[i] = ' ';
    270279          }
    271 
    272280          // Write to file
    273       fprintf(DataFile, "%s\n", Text);
    274 
    275           free(Text);
     281      fprintf(DataFile, "%s\n", Text.c_str());
    276282        }
    277283        else fprintf(DataFile, "Cannot interpret format identifier\n");
     
    286292
    287293        // Update datafile size service (not every time to avoid infinite loop)
    288         if (time(NULL) - DataSizeLastUpdate > SizeUpdateDelay) {
     294        if (time(NULL) - DataSizeLastUpdate > max(atoi(GetConfig("sizeupdate").c_str()), 1)) {
    289295      fflush(DataFile); // not continuously to reduce load
    290296
     
    300306//
    301307void DataHandler::commandHandler() {
    302  
     308 return;
    303309  if (getCommand() != LogCommand || LogFile == NULL) return;
    304310
     
    326332  }
    327333   
    328   // Update logfile size service
    329   if (time(NULL) - LogSizeLastUpdate > SizeUpdateDelay) {
     334  // Update logfile size service (not every time to avoid infinite loop)
     335  if (time(NULL) - LogSizeLastUpdate > atoi(GetConfig("sizeupdate").c_str())) {
    330336        LogSizeMB = FileSize(LogFile)/1024.0/1024.0;
    331337        LogSizeService->updateService();
     
    396402  static DataHandler DataInstance;
    397403 
    398   // Sleep until signal caught
    399   pause();
    400 }
     404  // Sleep until exit requested
     405  while (!DataInstance.ExitRequest) pause();
     406}
  • Evidence/Edd/Edd.cc

    r224 r229  
    2727QWidget *OpenHistory(char *Service, int Index) {
    2828
     29  QString Format;
     30  DimBrowser Browser;
    2931  class EvidenceHistory *Hist = Handler->GetHistory(Service);
    3032
    31   // Check if hitory service available
     33  // Check if history service available
    3234  if (Hist == NULL || Hist->GetFormat() == NULL) {
    3335        QMessageBox::warning(NULL, "Edd Message", QString("Could not retrieve history for service ") + Service ,QMessageBox::Ok);
    34         Handler->DropHistory(Service);
    35         return NULL;
    36   }
    37 
    38   QString Format = Hist->GetFormat();
     36
     37        // If service currently available, take its format
     38        char *Name, *Fmt;
     39
     40        Browser.getServices(Service);
     41        if (Browser.getNextService(Name, Fmt) != 0) Format = QString(Fmt);
     42        else {
     43          Handler->DropHistory(Service);
     44          return NULL;
     45        }
     46  }
     47
     48  if (Format.isEmpty()) Format = Hist->GetFormat();
    3949  Handler->DropHistory(Service);
    4050 
    41   //if (strlen(Hist->GetFormat()) == 1 && *Hist->GetFormat() != 'C') return new EddPlot(Service, Index);
    4251  if (Format.size() == 1 && Format[0] != 'C') return new EddPlot(Service, Index);
    4352  else return new EddText(Service);
     
    6877        QLineEdit(P), ServiceName(Name), Index(Index) {
    6978
    70  LastHist = NULL;
     79  LastHist = NULL;
    7180 
    7281  // Widget properties
     
    112121        return;
    113122  }
     123  else Pal.setColor(QPalette::Base, Qt::white);
    114124
    115125  // Message service backgound colour determined by severity
     
    933943  if (!EvidenceServer::ServiceOK(getInfo())) YEP(getInfo()->getName(), -1);
    934944  else {
    935         char *Text = EvidenceServer::ToString(getInfo());
    936         YEP(getInfo()->getName(), getInfo()->getTimestamp(), QByteArray((char *) getInfo()->getData(), getInfo()->getSize()), getInfo()->getFormat(), Text);
    937         free(Text);
     945        YEP(getInfo()->getName(),
     946                getInfo()->getTimestamp(),
     947                QByteArray((char *) getInfo()->getData(),
     948                getInfo()->getSize()), getInfo()->getFormat(),
     949                QString::fromStdString(EvidenceServer::ToString(getInfo())));
    938950  }
    939951}
     
    11831195    Plot->AddService("ARDUINO/Data", i);
    11841196  }
    1185   Layout->addWidget(Plot, 0, 2, 8, 7);     
     1197  Layout->addWidget(Plot, 0, 2, 9, 7);     
    11861198
    11871199  // Night sky monitor
     1200  Line = new EddLineDisplay("SQM/Message");
     1201  Line->setMaximumWidth(200);
     1202  Layout->addWidget(Line, 6, 0, 1, 2);     
     1203
    11881204  Line = new EddLineDisplay("SQM/NSB");
    1189   Layout->addWidget(Line, 6, 0, 1, 1);         
     1205  Layout->addWidget(Line, 7, 0, 1, 1);         
    11901206}
    11911207
     
    15541570  bool OK;
    15551571
    1556   // Find all services that are not history services and sort
     1572  // Find all DIM services and sort
    15571573  getServices("*");
    15581574  while ((Type = getNextService(Name, Format)) != 0) {
  • Evidence/Edd/Edd.pro

    r208 r229  
    66TARGET =
    77DEPENDPATH += .
    8 INCLUDEPATH += . .. /ihp/local/qwt-5.2.1/include $(DIMDIR)/dim ../../drsdaq ../../pixelmap
     8INCLUDEPATH += . .. $(QWTDIR)/include $(DIMDIR)/dim ../../drsdaq ../../pixelmap
    99
    1010# Input
    1111HEADERS += Edd.h
    1212SOURCES += Edd.cc ../Evidence.cc ../../drsdaq/RawDataCTX.cc ../../pixelmap/Pixel.cc ../../pixelmap/PixelMap.cc
    13 LIBS += -L/ihp/local/qwt-5.2.1/lib -lqwt $(DIMDIR)/linux/libdim.a
     13LIBS += -L$(QWTDIR)/lib -lqwt $(DIMDIR)/linux/libdim.a
  • Evidence/Evidence.cc

    r224 r229  
    99  - If the severity of a Message() call is FATAL, exit() will be called (with
    1010    this severity, the call to Message() is guranteed not to return).
    11   - Configuration data can be requested by GetConfig().
     11  - Configuration data can be requested by GetConfig() and non-blocking by GetConfigNB().
     12  - If the configuration file changes the signal SIGUSR1 is emitted which is caught by the standard
     13    signal handler. The handler invokes ConfigChanged() which can be redefined by the user application.
     14        The signal is delivered only to the main thread (where the constructor is executed) and thus
     15        blocking rpc can be made from it.
    1216  - Signal handlers to ignore common signals are installed.
    1317    These signals will then cause pause() to return which can be used
    1418        by the application to terminate gracefully.
    15   - The static method ToString() converts the contents of a
    16     DIMInfo service into text
     19  - The static method ToString() converts the contents of a DIMInfo service into text
    1720  - A terminate-handler is installed for catching unhandled C++ exceptions.
    1821
    19   Memory allocated by the non-static methods will be freed by the
    20   class destructor.
    21  
    2222  Oliver Grimm, June 2010
    2323 
     
    2727using namespace std;
    2828
     29EvidenceServer *ThisServer;
     30
     31//
     32// Internal configuration class of EvidenceServer
     33//
     34// Data that might be accessed by two threads are protected by mutex
     35
     36// Constructor
     37EvidenceServer::Config::Config(string Name): DimRpcInfo("ConfigRequest", NO_LINK), Name(Name) {
     38
     39  // Initialise
     40  int Ret;
     41  if ((Ret = pthread_mutex_init(&Mutex, NULL)) != 0) {
     42    ThisServer->Message(ThisServer->FATAL, "pthread_mutex_init() failed in Config constructor (%s)", strerror(Ret));
     43  }
     44  CurrentItem = string();
     45  ConfigTimeStamp = 0;
     46 
     47  // SIGUSR2 delivered to this thread if configuration file changes
     48  ThreadID = pthread_self();
     49
     50  // Subscribe to be informed on configuration file change
     51  Service = new DimInfo("Config/ModifyTime", NO_LINK, this);
     52}
     53
     54// Destructor
     55EvidenceServer::Config::~Config() {
     56 
     57  delete Service;
     58
     59  int Ret;
     60  if ((Ret = pthread_mutex_destroy(&Mutex)) != 0) {
     61        ThisServer->Message(ThisServer->ERROR, "pthread_mutex_destroy() failed in Config destructor (%s)", strerror(Ret));
     62  }
     63}
     64
     65// Track last modification time of configuration file
     66void EvidenceServer::Config::infoHandler() {
     67
     68  Lock();
     69  ConfigTimeStamp = getInfo()->getInt();
     70  Unlock();
     71
     72  if (pthread_kill(ThreadID, SIGUSR2) != 0) {
     73        ThisServer->Message(ThisServer->WARN, "Could not send signal SIGUSR2 to main thread");
     74  }
     75}
     76
     77// Receive answer to remote procedure call
     78void EvidenceServer::Config::rpcInfoHandler(){
     79
     80  Lock();
     81  // Update map
     82  List[CurrentItem].Value = string(getString(), getSize()-1);
     83  List[CurrentItem].Time = ConfigTimeStamp;
     84  // Clear to allow new rpc call
     85  CurrentItem.clear();
     86  Unlock();
     87}
     88
     89// Return configuration data if still up to date or empty string otherwise
     90string EvidenceServer::Config::GetConfig(string Item, string Default) {
     91
     92  string Result;
     93
     94  // If up-to-date data in configuration list available, return this
     95  Lock();
     96  if ((List.count(Item) > 0) && (List[Item].Time >= ConfigTimeStamp)) Result = List[Item].Value;
     97  Unlock();
     98  if (!Result.empty()) return Result;
     99
     100  // Blocking configuration request if in main thread
     101  if (pthread_self() == ThreadID) {
     102        DimRpcInfo Config((char *) "ConfigRequest", NO_LINK);
     103        Config.setData((char *) (Name + " " + Item).c_str());
     104
     105        // Check if successful
     106        if (!EvidenceServer::ServiceOK(&Config)) {
     107      if (Default.empty()) {
     108                ThisServer->Message(ThisServer->FATAL, "Configuration server unreachable, can't retrieve '%s'", Item.c_str());
     109          }
     110          else Result = Default;
     111        }
     112        else {
     113          if (Config.getSize() == 0) Result = Default;
     114          else Result = string(Config.getString(), Config.getSize()-1); // Retrieve string safely
     115    }
     116
     117        // Update configuration map     
     118        if (!Result.empty()) {
     119          Lock();
     120          List[Item].Value = Result;
     121          List[Item].Time = ConfigTimeStamp;
     122          Unlock();
     123        }       
     124  }
     125
     126  // Non-blocking configuration request fro other threads
     127  if (pthread_self() != ThreadID) {
     128        Lock();
     129        if (List.count(Item) > 0) {
     130          // New request possible only when answer to previous request received
     131          if (CurrentItem.empty()) {
     132                CurrentItem = Item;
     133                setData(((char *) (Name + " " + Item).c_str()));
     134          }
     135
     136          // Return current value
     137          Result = List[Item].Value;
     138          Unlock();
     139        }
     140  }
     141
     142  return Result;
     143}
     144
     145// Locking and unlocking for list access. Signal SIGUSR2 is also blocked.
     146void EvidenceServer::Config::Lock() {
     147
     148  int Ret = 0;
     149  sigset_t Set;
     150  //printf("Locking %u\n", pthread_self());
     151  Ret += abs(sigemptyset(&Set));
     152  Ret += abs(sigaddset(&Set, SIGUSR2));
     153  Ret += abs(pthread_sigmask(SIG_BLOCK, &Set, NULL));
     154  Ret += abs(pthread_mutex_lock(&Mutex));
     155 
     156  if (Ret != 0) {
     157        ThisServer->Message(ThisServer->FATAL, "Thread related call failed in Config::Lock()");
     158  }
     159}
     160
     161void EvidenceServer::Config::Unlock() {
     162
     163  int Ret = 0;
     164  sigset_t Set;
     165  //printf("  Unlocking %u\n", pthread_self());
     166
     167  Ret += abs(pthread_mutex_unlock(&Mutex));
     168  Ret += abs(sigemptyset(&Set));
     169  Ret += abs(sigaddset(&Set, SIGUSR2));
     170  Ret += abs(pthread_sigmask(SIG_UNBLOCK, &Set, NULL));
     171
     172  if (Ret != 0) {
     173        ThisServer->Message(ThisServer->FATAL, "Thread related call failed in Config::Unlock()");
     174  }
     175}
     176
     177
    29178//////////////////////////
    30179// EvidenceServer Class //
    31180//////////////////////////
    32181
    33 EvidenceServer *ThisServer;
    34 
    35182// Constructor starts server with given name
    36 EvidenceServer::EvidenceServer(const char *Name) {
     183EvidenceServer::EvidenceServer(const char *ServerName): Name(ServerName) {
    37184
    38185  // Initialize
     
    41188  ExitRequest = false;
    42189  ThisServer = this;
    43   ServerName = Name;
    44190
    45191  // Catch some signals
     
    48194  signal(SIGINT, &SignalHandler);   // CTRL-C
    49195  signal(SIGHUP, &SignalHandler);   // Terminal closed
     196 
     197  struct sigaction S;
     198  S.sa_handler = &SignalHandler;
     199  S.sa_flags = SA_RESTART;
     200  sigaction(SIGUSR2, &S, NULL);
    50201
    51202  // Catch C++ unhandled exceptions
    52203  set_terminate(Terminate);
    53204
    54   // Subscribe to modify service for keeping track of config file changes
    55   ModifyInfo = new class ConfigUpdate();
     205  // Configuration class (instantiate after signal handling for SIGUSR2 installed)
     206  ConfClass = new class Config(Name);
    56207
    57208  // Message service and initial message
    58   MessageService = new DimService((ServerName+"/Message").c_str(), (char *) "I:1;C", NULL, 0);
     209  MessageService = new DimService((Name+"/Message").c_str(), (char *) "I:1;C", NULL, 0);
    59210
    60211  string Rev(EVIDENCE_REVISION);
     
    62213
    63214  // Start server
    64   start(Name);
    65   addExitHandler(this); 
     215  start(ServerName);
     216  addExitHandler(this);
    66217}
    67218
     
    71222  Message(INFO, "Server stopped");
    72223 
    73   for (unsigned int i=0; i<ConfigList.size(); i++) delete[] ConfigList[i].Value;
    74   delete ModifyInfo;
     224  delete ConfClass;
    75225  delete MessageService;
    76226  delete MessageData;
     
    152302// Program terminates if data is missing and no default given. Actual configuration
    153303// request will be made only if config file has modification since last request.
    154 // The memory allocated by all calls to this function will be freed by
    155 // the destructor.
    156 char* EvidenceServer::GetConfig(string Item, const char *Default) {
    157  
    158   int ItemNo = -1;
    159  
    160   // Check if configuration request already in list
    161   for (unsigned int i=0; i<ConfigList.size(); i++) if (ConfigList[i].Name == Item) {
    162         // Return original value if still up to date
    163         if (ConfigList[i].Time >= ModifyInfo->LastModifyTime) return ConfigList[i].Value;
    164 
    165         // Otherwise, free memory of old value
    166         delete[] ConfigList[i].Value;
    167         ItemNo = i;
    168         break;
    169   }
    170 
    171   // Make configuration request
    172   DimRpcInfo Config((char *) "ConfigRequest", NO_LINK);
    173   Config.setData((char *) (ServerName + " " + Item).c_str());
    174   char *Result = Config.getString();
    175 
    176   // Terminate if not successful
    177   if (!EvidenceServer::ServiceOK(&Config)) {
    178     if (Default == NULL) Message(FATAL, "Configuration server unreachable, can't get '%s'", Item.c_str());
    179         Result = (char *) Default;
    180   }
    181 
    182   if (strlen(Result) == 0) {
    183     if (Default == NULL) Message(FATAL, "Missing configuration data '%s'", Item.c_str());
    184         Result = (char *) Default;
    185   }
    186 
    187   // Enlarge list if necessary
    188   if (ItemNo == -1) {
    189     struct ConfigItem New;
    190     ConfigList.push_back(New);
    191         ItemNo = ConfigList.size()-1;
    192   }
    193 
    194   // Create new entry in item list, allocate memory and copy data to this memory
    195   ConfigList[ItemNo].Name = Item;
    196   ConfigList[ItemNo].Value = new char [strlen(Result)+1];
    197   strcpy(ConfigList[ItemNo].Value, Result);
    198   ConfigList[ItemNo].Time = ModifyInfo->LastModifyTime;
    199 
    200   // Return address to configuration value 
    201   return ConfigList[ItemNo].Value;
    202 }
    203 
     304// If called from infoHandler(), a non-blocking request will be made
     305string EvidenceServer::GetConfig(string Item, string Default) {
     306
     307  string Result = ConfClass->GetConfig(Item, Default);
     308  if (Result.empty()) Message(FATAL, "Missing configuration data '%s'", Item.c_str());
     309  return Result;
     310}
    204311
    205312// ====== Static methods ======
     
    209316
    210317  static bool Called = false;
     318
     319  // If SIGUSR2, invoke call-back for configuraton change
     320  if (Signal == SIGUSR2) {
     321    ThisServer->ConfigChanged();
     322        return;
     323  }
    211324
    212325  // At first invocation just request exit
     
    261374
    262375
    263 // Translates DIMInfo to string (memory has to be freed by caller)
    264 // Static method, cannot report memory allocation errors via Message() but returns NULL
    265 char *EvidenceServer::ToString(DimInfo *Item) {
    266 
    267   char *Text;
    268 
     376// Translates DIMInfo safely to string (assures no inivalid memory accesses are made)
     377string EvidenceServer::ToString(DimInfo *I) {
     378
     379  ostringstream Text;
     380 
    269381  // Safety check
    270   if (Item->getSize() < 1) return NULL;
    271 
    272   // Message structure format handled
    273   if (strcmp(Item->getFormat(), "I:1;C") == 0) {
    274         struct Message *Msg = (struct Message *) Item->getData();
    275         if (asprintf(&Text, "%d %s", Msg->Severity, Msg->Text) == -1) return NULL;
    276         else return Text;
    277   }
    278  
    279   // Structure: print hex representation (3 characters per byte) 
    280   if (strlen(Item->getFormat()) != 1) {
    281     int Size = 3*Item->getSize()+1, N;
    282     if ((Text = (char *) malloc(Size)) == NULL) return NULL;
    283        
    284         char *CurrPos = Text;
    285         for (int i=0; i<Item->getSize(); i++) {
    286           N = snprintf(CurrPos, Size, "%02x ", *((char *) Item->getData() + i));
    287           if (N<0 || N>=Size) {
    288             free(Text);
    289                 if (asprintf(&Text, "Structure length %d bytes, buffer overflow in ToString()", Item->getSize()) == -1) return NULL;
    290                 else return Text;
    291           }
    292           Size -= N;
    293           CurrPos += N;
     382  if (I->getSize() < 1) return string();
     383
     384  // 'Message' service format handled here
     385  if (strcmp(I->getFormat(), "I:1;C") == 0 && I->getSize()>=(int) sizeof(struct Message)) {
     386        struct Message *Msg = (struct Message *) I->getData();
     387        // Safely extract string and limit to length of C string (padding might make it longer)
     388        string MsgText(Msg->Text, I->getSize()-sizeof(struct Message));
     389    //MsgText.erase(strlen(MsgText.c_str()));
     390        Text << Msg->Severity << " " << MsgText.erase(strlen(MsgText.c_str()));
     391
     392        return Text.str();
     393  }
     394 
     395  // Structure: print hex representation
     396  if (strlen(I->getFormat()) != 1) {
     397        for (int i=0; i<I->getSize(); i++) {
     398          Text << setw(2) << hex << *((char *) I->getData() + i) << " ";
    294399        }
    295         return Text;
    296   }
    297 
    298   // String: terminating \0 is enforced
    299   if (toupper(*(Item->getFormat())) == 'C') { 
    300     *(Item->getString() + Item->getSize() - 1) = '\0';
    301         if (asprintf(&Text, "%s", Item->getString()) == -1) return NULL;
    302         return Text;
     400        return Text.str();
     401  }
     402
     403  // String if format "C" and terminated with \0
     404  if (strcmp(I->getFormat(),"C")==0 && *((char *) I->getData()+I->getSize()-1)=='\0') { 
     405    Text << I->getString();
     406        return Text.str();
    303407  }
    304408
    305409  // Number array
    306410  int Size;
    307   switch (toupper(*(Item->getFormat()))) {
     411  switch (*(I->getFormat())) {
     412    case 'C': Size = sizeof(char);              break;
    308413    case 'I':
    309414    case 'L': Size = sizeof(int);               break;
     
    312417    case 'D': Size = sizeof(double);    break;
    313418    case 'X': Size = sizeof(long long); break;
    314     default: return NULL;
    315   }
    316 
    317   int Max, Mem = Item->getSize()*Size*4+1;
    318   char *Pos;
    319 
    320   if ((Text = (char *) malloc(Mem)) == NULL) return NULL;
    321 
    322   *Text = '\0';
    323   for (int i=0; i<Item->getSize()/Size; i++) {
    324         Pos = Text+strlen(Text);
    325         Max = Mem-strlen(Text);
    326 
    327         switch (toupper(*(Item->getFormat()))) {
     419    default: return string();
     420  }
     421
     422  for (int i=0; i<I->getSize()/Size; i++) {
     423        // Space between entries
     424    if (i != 0) Text << " ";
     425
     426        // Translate data
     427        switch (*(I->getFormat())) {
     428      case 'C': Text << *((char *) I->getData() + i);
     429                                break;
    328430      case 'I':
    329       case 'L': snprintf(Pos, Max, "%d ", *((int *) Item->getData() + i));
     431      case 'L': Text << *((int *) I->getData() + i);
    330432                                break;
    331       case 'S': snprintf(Pos, Max, "%hd ", *((short *) Item->getData() + i));
     433      case 'S': Text << *((short *) I->getData() + i);
    332434                                break;
    333       case 'F': snprintf(Pos, Max, "%.5f ", *((float *) Item->getData() + i));
     435      case 'F': Text << *((float *) I->getData() + i);
    334436                                break;
    335       case 'D': snprintf(Pos, Max, "%.5f ", *((double *) Item->getData() + i));
     437      case 'D': Text << *((double *) I->getData() + i);
    336438                                break;
    337       case 'X': snprintf(Pos, Max, "%lld ", *((long long *) Item->getData() + i));
     439      case 'X': Text << *((long long *) I->getData() + i);
    338440                                break;
    339441        }
    340442  }
    341443 
    342   return Text;
    343 }
     444  return Text.str();
     445}
     446
    344447
    345448// Checks if service contents indicates not available
     
    355458          (memcmp(Item->getData(), NO_LINK, Item->getSize()) == 0));
    356459}
     460
     461
     462// Tokenize std::string using given delimeter list
     463vector<string> EvidenceServer::Tokenize(const string &String, const string &Delimiters) {
     464
     465  vector<string> Tokens;
     466  string::size_type Next, EndNext=0;
     467   
     468  while (EndNext != string::npos) {
     469    // Find next token
     470    Next = String.find_first_not_of(Delimiters, EndNext);
     471    EndNext = String.find_first_of(Delimiters, Next);
     472
     473        // Stop if end of string reached
     474        if (Next == string::npos) break;
     475
     476    // Add token to vector.
     477    Tokens.push_back(String.substr(Next, EndNext - Next));
     478  }
     479 
     480  return Tokens;
     481}
     482
    357483
    358484///////////////////////////
  • Evidence/Evidence.h

    r224 r229  
    55#include <stdarg.h>
    66#include <string>
     7#include <sstream>
     8#include <iomanip>
    79#include <errno.h>
    810#include <vector>
     11#include <map>
     12
    913#include <exception>
    1014#include <cxxabi.h>
     
    1721#define EVIDENCE_REVISION "$Revision$"
    1822
     23
    1924// Class declation of Evidence server
    2025class EvidenceServer: public DimServer {
    2126
    22   private:
    23         // This class will contain in LastModifyTime always
    24         // the unix time of the last config file update
    25         class ConfigUpdate: public DimClient, public DimRpcInfo {
    26           DimInfo *ModifyInfo;
    27          
     27        // Internal class for configuration requests
     28        class Config: public DimClient, public DimRpcInfo {
     29
     30                pthread_mutex_t Mutex;
     31                std::string Name;
     32                DimInfo *Service;
     33                int ConfigTimeStamp;
     34                std::string CurrentItem;
     35                pthread_t ThreadID;
     36
     37                struct Item {
     38                  std::string Value;
     39                  int Time;
     40                };
     41                std::map<std::string, struct Item> List;
     42
    2843          public:
    29             ConfigUpdate(): DimRpcInfo("ConfigRequest", NO_LINK) {
    30               LastModifyTime = 0;
    31                   ModifyInfo = new DimInfo("Config/ModifyTime", NO_LINK, this);
    32             }
    33                 ~ConfigUpdate() {
    34                   delete ModifyInfo;
    35                 }
    36             void Request(const char *What){
    37               setData((char *) What);
    38             }
     44                Config(std::string);
     45                ~Config();
    3946
    40             void infoHandler(){
    41               if (EvidenceServer::ServiceOK(getInfo())) LastModifyTime = getInfo()->getInt();
    42             }
    43 
    44             void rpcInfoHandler(){
    45                   //printf("Received %s\n", getString());
    46             }
    47 
    48                 int LastModifyTime;
     47                std::string GetConfig(std::string, std::string);
     48                void Lock();
     49                void Unlock();
     50                void infoHandler();
     51                void rpcInfoHandler();
    4952        };
    50 
    51   private:
    52 
    53         struct ConfigItem {
    54           std::string Name;
    55           char *Value;
    56           int Time;
    57         };
    58         std::vector<struct ConfigItem> ConfigList;
    5953
    6054        struct Message {
     
    6357        };
    6458
    65         std::string ServerName;
     59        std::string Name;
    6660    DimService *MessageService;
    6761        struct Message *MessageData;
    68         class ConfigUpdate *ModifyInfo;
     62        class Config *ConfClass;
    6963       
    7064    static void SignalHandler(int); // static for signal()
     
    7266        void errorHandler(int, int, char *);
    7367        void exitHandler(int);
    74        
     68        virtual void ConfigChanged() {};
     69
    7570  public:
    7671    EvidenceServer(const char *);
     
    8176        void Message(MessageType, const char *, ...);
    8277        void SendToLog(const char *, ...);
    83         char* GetConfig(std::string, const char * = NULL);
    84         static char* ToString(DimInfo *);
     78        std::string GetConfig(std::string, std::string = std::string());
     79        static std::string ToString(DimInfo *);
    8580        static bool ServiceOK(DimInfo *);
    8681        static bool ServiceOK(DimRpcInfo *);
     82        static std::vector<std::string> Tokenize(const std::string &, const std::string & = " ");
    8783
    8884    bool ExitRequest;
  • Evidence/History.cc

    r224 r229  
    2323
    2424#include <string>
    25 #include <vector>
     25#include <sstream>
     26#include <map>
    2627#include <math.h>
    2728#include <float.h>
    2829#include <sys/stat.h>
     30#include <sys/time.h>
    2931
    3032using namespace std;
     
    4345          string Format;
    4446        };
    45         vector<struct Item> List;
     47        map<string, struct Item> Map;
    4648       
    4749        DimInfo *ServerList;
    4850        char *Directory;
    49         char *Change;
     51        string Change;
    5052
    5153    void infoHandler();
     
    6769                                                         Directory(Dir) {
    6870
    69   // List of minimum required change for addition to history buffer
     71  // Map of minimum required change for addition to history buffer
    7072  Change = GetConfig("minchange", " ");
    7173
     
    7981
    8082  delete ServerList;
    81   while (List.size() != 0) RemoveService(List[0].DataItem->getName());
     83  while (Map.size() != 0) RemoveService((*Map.begin()).first);
    8284}
    8385
     
    106108  // If service is SERVICE_LIST, scan and subscribe/unsubscribe to services
    107109  if (strstr(I->getName(), "/SERVICE_LIST") != NULL) {
     110
     111        // Bug fix for empty SERVICE_LIST
     112        if (strlen(I->getString()) == 0) {
     113          string Tmp(I->getName());
     114          RemoveService(I->getName());
     115          AddService(Tmp.c_str(), (char *) "C");
     116          return;
     117        }
     118
    108119        char *Type, *Name = strtok(I->getString(), "+-!|");
    109120        while (Name != NULL) {
     
    124135  // ====== Part B: Handle history service ===
    125136
    126   // Identify index of service
    127   int Service;
    128   for (Service=0; Service<List.size(); Service++) if (I == List[Service].DataItem) break;
    129   if (Service == List.size()) return;  // Service not found
    130 
    131   // Ignore empty services
    132   if (I->getSize()==0 || I->getTimestamp()==0) return;
    133 
     137  char *Service = I->getName();
     138
     139  // Check if service known and ignore empty service
     140  if (Map.count(Service) == 0 || I->getSize()==0 || I->getTimestamp()==0) return;
     141 
    134142  // Resize buffer if necessary
    135   if (List[Service].Buffer.size() < REQUEST_NUM*I->getSize()) {
    136         if (REQUEST_NUM*I->getSize() < MAX_SIZE_KB*1024) List[Service].Buffer.resize(REQUEST_NUM*I->getSize());
    137   }
    138 
    139   // If data is number of single type, a minumum change might be requested before addind to history
    140   if (strcmp(I->getFormat(),"C") != 0 && strlen(I->getFormat())==1) {
     143  if (Map[Service].Buffer.size() < REQUEST_NUM*I->getSize()) {
     144        if (REQUEST_NUM*I->getSize() < MAX_SIZE_KB*1024) Map[Service].Buffer.resize(REQUEST_NUM*I->getSize());
     145  }
     146
     147  // If data is number of single type, check minumum change before adding to history
     148  if (strcmp(I->getFormat(), "C") != 0) {
    141149        // Calculate sum of all number in array
    142         char *Text = EvidenceServer::ToString(I);
    143         char *Token = strtok(Text, " ");
    144         double Sum = 0;
    145         while (Token != NULL) {
    146           Sum += atof(Token);
    147       Token = strtok(NULL, " ");
    148         }
    149         free(Text);
     150        istringstream Text(EvidenceServer::ToString(I));
     151        double Num, Sum = 0;
     152        while (Text.good()) {
     153          Text >> Num;
     154          Sum += fabs(Num);
     155        }
    150156
    151157        // Minimum change?
    152         if (fabs(Sum-List[Service].LastValue) < fabs(List[Service].MinAbsChange)) return;
    153         List[Service].LastValue = Sum;
     158        if (fabs(Sum-Map[Service].LastValue) < fabs(Map[Service].MinAbsChange)) return;
     159        Map[Service].LastValue = Sum;
    154160  }
    155161 
    156162  // Check if data fits into buffer
    157   if (List[Service].Buffer.size() < I->getSize() + sizeof(int)+ 2*sizeof(EvidenceHistory::Item)) return;
    158 
    159   int Size = I->getSize() + 2*sizeof(EvidenceHistory::Item), Next = List[Service].Next;
     163  if (Map[Service].Buffer.size() < I->getSize() + sizeof(int)+ 2*sizeof(EvidenceHistory::Item)) return;
     164
     165  int Size = I->getSize() + 2*sizeof(EvidenceHistory::Item), Next = Map[Service].Next;
    160166  void *WrapPos = NULL;
    161   char *Buffer = &List[Service].Buffer[0];
     167  char *Buffer = &Map[Service].Buffer[0];
    162168  int Oldest = *(int *) Buffer;
    163169
    164170  // Check if buffer wrap-around (write wrap mark after Oldest is adjusted)
    165   if (Next + Size >= List[Service].Buffer.size()) {
     171  if (Next + Size >= Map[Service].Buffer.size()) {
    166172    WrapPos = Buffer + Next;
    167173    Next = sizeof(int);
     
    199205  memcpy(Buffer + Next, &EvidenceHistory::EndMark, sizeof(EvidenceHistory::EndMark));
    200206 
    201   List[Service].Next = Next;
     207  Map[Service].Next = Next;
    202208}
    203209
     
    206212void History::rpcHandler() {
    207213
    208   // Search for history buffer
    209   for (int i=0; i<List.size(); i++) {
    210     if (strcmp(List[i].DataItem->getName(), getString()) == 0) {
    211           char *Buffer = new char [List[i].Format.size()+1+List[i].Buffer.size()];
    212           strcpy(Buffer, List[i].Format.c_str());
    213           memcpy(Buffer+List[i].Format.size()+1, &List[i].Buffer[0], List[i].Buffer.size());
    214 //        setData((void *) &List[i].Buffer[0], List[i].Buffer.size());
    215           setData((void *) Buffer, List[i].Format.size()+1+List[i].Buffer.size());
    216           delete[] Buffer;
    217           return;
    218         }
     214  char *Name = getString();
     215 
     216  // Search for history buffer in memory
     217  if (Map.count(Name) == 1) {
     218        char *Buffer = new char [Map[Name].Format.size()+1+Map[Name].Buffer.size()];
     219        strcpy(Buffer, Map[Name].Format.c_str());
     220        memcpy(Buffer+Map[Name].Format.size()+1, &Map[Name].Buffer[0], Map[Name].Buffer.size());
     221        setData((void *) Buffer, Map[Name].Format.size()+1+Map[Name].Buffer.size());
     222        delete[] Buffer;
     223        return;
    219224  }
    220225
    221226  // Try to open history file if not found in memory
    222   FILE *File = OpenFile(getString(), "rb");
     227  FILE *File = OpenFile(Name, "rb");
    223228  if (File == NULL) {
    224229    setData(NULL, 0);
     
    232237        fseek(File, sizeof(int), SEEK_SET); // Skip 'Next' pointer
    233238        if ((fread(Buffer, sizeof(char), Size-sizeof(int), File) != Size-sizeof(int)) || (ferror(File) != 0)) {
    234           Message(WARN, "Error reading history file '%s' in rpcHandler()", getString());
     239          Message(WARN, "Error reading history file '%s' in rpcHandler()", Name);
    235240          setData(NULL, 0);             // Default response
    236241        }
     
    239244  }
    240245 
    241   if (fclose(File) != 0) Message(WARN, "Error closing history file '%s' in rpcHandler()", getString());
     246  if (fclose(File) != 0) Message(WARN, "Error closing history file '%s' in rpcHandler()", Name);
    242247}
    243248
     
    248253void History::AddService(string Name, const char *Format) {
    249254
    250   // Check if already subscribed to this service
    251   for (int i=0; i<List.size(); i++) {
    252         if (Name == List[i].DataItem->getName()) return;
    253   }
    254 
    255   struct Item New;
    256   New.LastValue = DBL_MAX;
    257   New.Format = Format;
    258 
     255  // Return if already subscribed to this service
     256  if (Map.count(Name) != 0) return;
     257
     258  // Create new service subscription
     259  Map[Name].LastValue =  DBL_MAX;
     260  Map[Name].Format = Format;
     261  Map[Name].MinAbsChange = 0.0;
     262 
    259263  // Set minimum required change if given in configuratrion
    260   char *Pnt = strstr(Change, Name.c_str());
    261 
    262   if (Pnt != NULL && *(Pnt+Name.size()) == ':') New.MinAbsChange = atof(Pnt+Name.size()+1);
    263   else New.MinAbsChange = 0;
     264  size_t Pos = Change.find(Name+":");
     265  if (Pos != string::npos) Map[Name].MinAbsChange = atof(Change.c_str() + Pos + Name.size() + 1);
    264266
    265267  // Load history buffer from file if existing
     
    270272
    271273    // If current buffer too small, resize
    272         if (Size > New.Buffer.size()) New.Buffer.resize(Size);
     274        if (Size > Map[Name].Buffer.size()) Map[Name].Buffer.resize(Size);
    273275
    274276        // Read next pointer
    275     fread(&New.Next, sizeof(New.Next), 1, File);
     277    fread(&Map[Name].Next, sizeof(Map[Name].Next), 1, File);
    276278        // Skip format string
    277279        while (fgetc(File) != 0 && feof(File) == 0) {}
    278280        // Read buffer
    279     fread(&New.Buffer[0], sizeof(char), Size, File);
     281    fread(&Map[Name].Buffer[0], sizeof(char), Size, File);
    280282
    281283        if (ferror(File) != 0) {
    282284          Message(WARN, "Error reading history file '%s' in AddService()", Name.c_str());
    283           New.Buffer.clear();
     285          Map[Name].Buffer.clear();
    284286        }
    285287    if (fclose(File) != 0) Message(WARN, "Error closing history file '%s' in AddService()", Name.c_str());;
     
    287289
    288290  // If no buffer loaded, allocate empty buffer
    289   if (New.Buffer.empty()) {
    290         New.Buffer.resize(MIN_SIZE_KB*1024);
    291         memset(&New.Buffer[0], 0, New.Buffer.size());
    292         *(int *) &New.Buffer[0] = 4;
    293         New.Next = 4;
     291  if (Map[Name].Buffer.empty()) {
     292        Map[Name].Buffer.resize(MIN_SIZE_KB*1024);
     293        memset(&Map[Name].Buffer[0], 0, Map[Name].Buffer.size());
     294        *(int *) &Map[Name].Buffer[0] = 4;
     295        Map[Name].Next = 4;
    294296  }
    295297 
    296298  // Subscribe to service
    297   New.DataItem = new DimStampedInfo(Name.c_str(), NO_LINK, this);
    298 
    299   List.push_back(New);
     299  Map[Name].DataItem = new DimStampedInfo(Name.c_str(), NO_LINK, this);
    300300}
    301301
     
    306306void History::RemoveService(string Name) {
    307307
    308   // Find service index
    309   vector<struct Item>::iterator E;
    310   for (E=List.begin(); E<List.end(); ++E) if (Name == (*E).DataItem->getName()) {
    311         // Delete subscription first so handler and not called anymore
    312         delete (*E).DataItem;
    313 
    314         // Save history buffer
    315         FILE *File = OpenFile(Name, "wb");
    316         if (File != NULL) {
    317       fwrite(&(*E).Next, sizeof((*E).Next), 1, File);                                   // Next pointer
    318       fwrite((*E).Format.c_str(), (*E).Format.size()+1, 1, File);               // Format
    319       fwrite(&(*E).Buffer[0], sizeof(char), (*E).Buffer.size(), File);  // Buffer
    320 
    321           // If error, try to delete (possibly erroneous) file
    322           if (ferror(File) != 0) {
    323                 if (remove(Name.c_str()) == -1) Message(WARN, "Error writing history file '%s' in RemoveService(), could also not delete file", Name.c_str());
    324                 else Message(WARN, "Error writing history file '%s' in RemoveService(), deleted file", Name.c_str());
    325           }
    326       if (fclose(File) != 0) Message(WARN, "Error closing history file '%s' in RemoveService()", Name.c_str());;
    327         }
    328        
    329         List.erase(E);
    330   }
     308  // Check if actually subscribed to service 
     309  if (Map.count(Name) == 0) return;
     310
     311  // Delete subscription first so handler and not called anymore
     312  delete Map[Name].DataItem;
     313
     314  // Save history buffer
     315  FILE *File = OpenFile(Name, "wb");
     316  if (File != NULL) {
     317    fwrite(&Map[Name].Next, sizeof(Map[Name].Next), 1, File);                                   // Next pointer
     318    fwrite(Map[Name].Format.c_str(), Map[Name].Format.size()+1, 1, File);               // Format
     319    fwrite(&Map[Name].Buffer[0], sizeof(char), Map[Name].Buffer.size(), File);  // Buffer
     320
     321        // If error, try to delete (possibly erroneous) file
     322        if (ferror(File) != 0) {
     323          if (remove(Name.c_str()) == -1) Message(WARN, "Error writing history file '%s' in RemoveService(), could also not delete file", Name.c_str());
     324          else Message(WARN, "Error writing history file '%s' in RemoveService(), deleted file", Name.c_str());
     325        }
     326    if (fclose(File) != 0) Message(WARN, "Error closing history file '%s' in RemoveService()", Name.c_str());;
     327  }
     328
     329  Map.erase(Name);
    331330}
    332331
     
    377376 
    378377  // Sleep until signal caught
    379   pause();
    380 }
     378  while (!Hist.ExitRequest) pause();
     379}
  • Evidence/readme.txt

    r227 r229  
    2020to run.
    2121
    22 - Oliver Grimm, 18/1/2010
    2322
    2423Version history
     
    4443                        service for each observed server SERVERNAME/AlarmLevel contains the highest
    4544                        level that occurred in the past. Reset of alarm level only via a DIM command.
     4519/6/2010       ToString() now returns std::string
     4623/6/2010       GetConfig() returns std::string. Non-blocking configuration request in case
     47                        GetConfig() not called from main thread. Access to configuration information
     48                        internally mutex protected. Signal SIGUSR2 send to main thread upon configuration
     49                        file change, signal handler invokes (virtual) method ConfigChanged().
     5024/6/2010       Workaround for erroneous /SERVICE_LIST updates. Added static tokenize method to
     51                        Evidence class.
    4652
    4753
Note: See TracChangeset for help on using the changeset viewer.