- Timestamp:
- 06/24/10 07:51:15 (15 years ago)
- Location:
- Evidence
- Files:
-
- 1 added
- 10 edited
Legend:
- Unmodified
- Added
- Removed
-
Evidence/Alarm.cc
r227 r229 80 80 81 81 // 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++) { 85 85 // 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]; 92 89 else N.Email = string(); 93 90 … … 102 99 103 100 List.push_back(N); 104 Token = strtok(NULL, " \t");105 101 } 106 102 … … 247 243 248 244 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 24 24 using namespace std; 25 25 26 27 26 // Class declaration 28 27 class Bridge: public DimClient, public EvidenceServer { 29 28 30 29 struct Item { 31 string Name;32 30 DimCommand *Command; 33 31 DimStampedInfo *DataItem; … … 35 33 char *Data; 36 34 }; 37 vector<struct Item> List;35 map<string, struct Item> Map; 38 36 39 37 DimInfo *ServerList; … … 41 39 void infoHandler(); 42 40 void commandHandler(); 41 public: 43 42 void AddService(string, char *, int); 44 43 void RemoveService(string); 45 44 void BugFix(); 45 46 46 public: 47 47 Bridge(char *, int); … … 63 63 Bridge::~Bridge() { 64 64 65 while ( List.size() != 0) RemoveService(List[0].Name);65 while (Map.size() != 0) RemoveService((*Map.begin()).first); 66 66 delete ServerList; 67 67 } … … 77 77 78 78 // 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()); 80 81 char *Token = strtok(I->getString(), "+-!@"); 81 82 while (Token != NULL) { … … 94 95 // If service is SERVICE_LIST, scan and subscribe/unsubscribe to services 95 96 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 96 106 char *Format, *Name = strtok(I->getString(), "+-!|"); 97 107 while (Name != NULL) { … … 131 141 } 132 142 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()); 146 155 } 147 156 … … 161 170 162 171 // 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; 166 173 167 174 // 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 170 180 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); 177 185 } 178 186 … … 181 189 void Bridge::RemoveService(string Name) { 182 190 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); 192 200 } 193 201 … … 206 214 207 215 // Sleep until signal caught 208 pause();209 } 216 while (!Class.ExitRequest) pause(); 217 } -
Evidence/Config.cc
r224 r229 67 67 FileContent = NULL; 68 68 69 // Signaling interferes with inotify() mechnism 70 signal(SIGUSR2, SIG_IGN); 71 69 72 // Initialise mutex (errno is not set by pthread_mutex_init()) 70 73 if (pthread_mutex_init(&Mutex, NULL) != 0) { … … 266 269 Notify = -1; 267 270 } 268 271 269 272 // Sleep until file changes or signal caught 270 273 while (!Config.ExitRequest) { 271 274 if (Notify != -1) { 272 read(Notify, &Event, sizeof(Event)); 273 Config.ConfigChanged(); 275 if (read(Notify, &Event, sizeof(Event)) == sizeof(Event)) Config.ConfigChanged(); 274 276 } 275 277 else pause(); -
Evidence/DColl.cc
r224 r229 19 19 #include <string> 20 20 #include <sstream> 21 #include <iostream> 21 22 #include <vector> 22 23 #include <sys/stat.h> … … 44 45 float DataSizeMB, LogSizeMB; 45 46 int DataSizeLastUpdate, LogSizeLastUpdate; 46 char *BaseDir;47 47 DimService *LogSizeService, *DataSizeService, *DataFilename; 48 int SizeUpdateDelay;49 48 int TimeForNextFile; 50 int RollOver;51 49 52 50 vector<regex_t> RegEx; 53 51 54 52 void infoHandler(); 55 53 void commandHandler(); … … 57 55 void RemoveService(string); 58 56 off_t FileSize(FILE *); 59 57 void ConfigChanged(); 58 60 59 public: 61 60 DataHandler(); … … 63 62 }; 64 63 64 void DataHandler::ConfigChanged() { 65 //printf("Handler called in PID %u\n", pthread_self()); 66 } 67 65 68 // 66 69 // Constructor … … 80 83 TimeForNextFile = 0; 81 84 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"); 86 89 87 90 // 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) { 89 92 Message(FATAL, "Could not open log file (%s)", strerror(errno)); 90 93 } 91 94 92 95 // Create services for file sizes and data file name 93 96 DataSizeMB = 0; … … 100 103 101 104 // Compile regular expressions 102 char *Exclude = GetConfig("exclude");103 char *Token = strtok(Exclude, "\t ");104 105 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); 108 111 if (Ret != 0) { 109 112 char Err[200]; 110 113 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); 112 115 } 113 116 else RegEx.push_back(R); 114 115 Token = strtok(NULL, "\t "); 116 } 117 117 } 118 118 119 // Provide logging command 119 120 LogCommand = new DimCommand("DColl/Log", (char *) "C", this); … … 158 159 void DataHandler::infoHandler() { 159 160 161 // Check if service available 160 162 DimInfo *I = getInfo(); 161 162 // Check if service available163 163 if (!ServiceOK(I)) return; 164 164 … … 166 166 // ====== Part A: Handle service subscriptions === 167 167 // 168 // Services are added here, removal only in constructor.168 // Services are added here, removal only in destructor. 169 169 170 170 // If service is DIS_DNS/SERVER_LIST, subscribe to all SERVICE_LIST services … … 182 182 // Subscribe to all services (but not to commands and RPCs) 183 183 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 184 193 char *Name = strtok(I->getString(), "+-!|"); 185 194 while (Name != NULL) { … … 211 220 212 221 // 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++; 214 223 if (mktime(T) == -1) Message(ERROR, "mktime() failed, check filename"); 215 224 216 225 // Create direcory if not existing (ignore error if already existing) 217 226 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) { 219 228 Message(FATAL, "asprintf() failed, could not create direcory name"); 220 229 } … … 240 249 T->tm_sec = 0; 241 250 T->tm_min = 0; 242 T->tm_hour = RollOver;251 T->tm_hour = atoi(GetConfig("rollover").c_str()); 243 252 TimeForNextFile = mktime(T); 244 253 } … … 261 270 262 271 // 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()) { 266 275 // 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++) { 268 277 if (Text[i] == '\n') Text[i] = '\\'; 269 278 else if (iscntrl(Text[i])) Text[i] = ' '; 270 279 } 271 272 280 // Write to file 273 fprintf(DataFile, "%s\n", Text); 274 275 free(Text); 281 fprintf(DataFile, "%s\n", Text.c_str()); 276 282 } 277 283 else fprintf(DataFile, "Cannot interpret format identifier\n"); … … 286 292 287 293 // 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)) { 289 295 fflush(DataFile); // not continuously to reduce load 290 296 … … 300 306 // 301 307 void DataHandler::commandHandler() { 302 308 return; 303 309 if (getCommand() != LogCommand || LogFile == NULL) return; 304 310 … … 326 332 } 327 333 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())) { 330 336 LogSizeMB = FileSize(LogFile)/1024.0/1024.0; 331 337 LogSizeService->updateService(); … … 396 402 static DataHandler DataInstance; 397 403 398 // Sleep until signal caught399 pause();400 } 404 // Sleep until exit requested 405 while (!DataInstance.ExitRequest) pause(); 406 } -
Evidence/Edd/Edd.cc
r224 r229 27 27 QWidget *OpenHistory(char *Service, int Index) { 28 28 29 QString Format; 30 DimBrowser Browser; 29 31 class EvidenceHistory *Hist = Handler->GetHistory(Service); 30 32 31 // Check if hi tory service available33 // Check if history service available 32 34 if (Hist == NULL || Hist->GetFormat() == NULL) { 33 35 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(); 39 49 Handler->DropHistory(Service); 40 50 41 //if (strlen(Hist->GetFormat()) == 1 && *Hist->GetFormat() != 'C') return new EddPlot(Service, Index);42 51 if (Format.size() == 1 && Format[0] != 'C') return new EddPlot(Service, Index); 43 52 else return new EddText(Service); … … 68 77 QLineEdit(P), ServiceName(Name), Index(Index) { 69 78 70 LastHist = NULL;79 LastHist = NULL; 71 80 72 81 // Widget properties … … 112 121 return; 113 122 } 123 else Pal.setColor(QPalette::Base, Qt::white); 114 124 115 125 // Message service backgound colour determined by severity … … 933 943 if (!EvidenceServer::ServiceOK(getInfo())) YEP(getInfo()->getName(), -1); 934 944 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()))); 938 950 } 939 951 } … … 1183 1195 Plot->AddService("ARDUINO/Data", i); 1184 1196 } 1185 Layout->addWidget(Plot, 0, 2, 8, 7);1197 Layout->addWidget(Plot, 0, 2, 9, 7); 1186 1198 1187 1199 // Night sky monitor 1200 Line = new EddLineDisplay("SQM/Message"); 1201 Line->setMaximumWidth(200); 1202 Layout->addWidget(Line, 6, 0, 1, 2); 1203 1188 1204 Line = new EddLineDisplay("SQM/NSB"); 1189 Layout->addWidget(Line, 6, 0, 1, 1);1205 Layout->addWidget(Line, 7, 0, 1, 1); 1190 1206 } 1191 1207 … … 1554 1570 bool OK; 1555 1571 1556 // Find all services that are not historyservices and sort1572 // Find all DIM services and sort 1557 1573 getServices("*"); 1558 1574 while ((Type = getNextService(Name, Format)) != 0) { -
Evidence/Edd/Edd.pro
r208 r229 6 6 TARGET = 7 7 DEPENDPATH += . 8 INCLUDEPATH += . .. /ihp/local/qwt-5.2.1/include $(DIMDIR)/dim ../../drsdaq ../../pixelmap8 INCLUDEPATH += . .. $(QWTDIR)/include $(DIMDIR)/dim ../../drsdaq ../../pixelmap 9 9 10 10 # Input 11 11 HEADERS += Edd.h 12 12 SOURCES += 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.a13 LIBS += -L$(QWTDIR)/lib -lqwt $(DIMDIR)/linux/libdim.a -
Evidence/Evidence.cc
r224 r229 9 9 - If the severity of a Message() call is FATAL, exit() will be called (with 10 10 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. 12 16 - Signal handlers to ignore common signals are installed. 13 17 These signals will then cause pause() to return which can be used 14 18 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 17 20 - A terminate-handler is installed for catching unhandled C++ exceptions. 18 21 19 Memory allocated by the non-static methods will be freed by the20 class destructor.21 22 22 Oliver Grimm, June 2010 23 23 … … 27 27 using namespace std; 28 28 29 EvidenceServer *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 37 EvidenceServer::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 55 EvidenceServer::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 66 void 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 78 void 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 90 string 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. 146 void 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 161 void 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 29 178 ////////////////////////// 30 179 // EvidenceServer Class // 31 180 ////////////////////////// 32 181 33 EvidenceServer *ThisServer;34 35 182 // Constructor starts server with given name 36 EvidenceServer::EvidenceServer(const char * Name) {183 EvidenceServer::EvidenceServer(const char *ServerName): Name(ServerName) { 37 184 38 185 // Initialize … … 41 188 ExitRequest = false; 42 189 ThisServer = this; 43 ServerName = Name;44 190 45 191 // Catch some signals … … 48 194 signal(SIGINT, &SignalHandler); // CTRL-C 49 195 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); 50 201 51 202 // Catch C++ unhandled exceptions 52 203 set_terminate(Terminate); 53 204 54 // Subscribe to modify service for keeping track of config file changes55 ModifyInfo = new class ConfigUpdate();205 // Configuration class (instantiate after signal handling for SIGUSR2 installed) 206 ConfClass = new class Config(Name); 56 207 57 208 // 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); 59 210 60 211 string Rev(EVIDENCE_REVISION); … … 62 213 63 214 // Start server 64 start( Name);65 addExitHandler(this); 215 start(ServerName); 216 addExitHandler(this); 66 217 } 67 218 … … 71 222 Message(INFO, "Server stopped"); 72 223 73 for (unsigned int i=0; i<ConfigList.size(); i++) delete[] ConfigList[i].Value; 74 delete ModifyInfo; 224 delete ConfClass; 75 225 delete MessageService; 76 226 delete MessageData; … … 152 302 // Program terminates if data is missing and no default given. Actual configuration 153 303 // 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 305 string 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 } 204 311 205 312 // ====== Static methods ====== … … 209 316 210 317 static bool Called = false; 318 319 // If SIGUSR2, invoke call-back for configuraton change 320 if (Signal == SIGUSR2) { 321 ThisServer->ConfigChanged(); 322 return; 323 } 211 324 212 325 // At first invocation just request exit … … 261 374 262 375 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) 377 string EvidenceServer::ToString(DimInfo *I) { 378 379 ostringstream Text; 380 269 381 // 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) << " "; 294 399 } 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(); 303 407 } 304 408 305 409 // Number array 306 410 int Size; 307 switch (toupper(*(Item->getFormat()))) { 411 switch (*(I->getFormat())) { 412 case 'C': Size = sizeof(char); break; 308 413 case 'I': 309 414 case 'L': Size = sizeof(int); break; … … 312 417 case 'D': Size = sizeof(double); break; 313 418 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; 328 430 case 'I': 329 case 'L': snprintf(Pos, Max, "%d ", *((int *) Item->getData() + i));431 case 'L': Text << *((int *) I->getData() + i); 330 432 break; 331 case 'S': snprintf(Pos, Max, "%hd ", *((short *) Item->getData() + i));433 case 'S': Text << *((short *) I->getData() + i); 332 434 break; 333 case 'F': snprintf(Pos, Max, "%.5f ", *((float *) Item->getData() + i));435 case 'F': Text << *((float *) I->getData() + i); 334 436 break; 335 case 'D': snprintf(Pos, Max, "%.5f ", *((double *) Item->getData() + i));437 case 'D': Text << *((double *) I->getData() + i); 336 438 break; 337 case 'X': snprintf(Pos, Max, "%lld ", *((long long *) Item->getData() + i));439 case 'X': Text << *((long long *) I->getData() + i); 338 440 break; 339 441 } 340 442 } 341 443 342 return Text; 343 } 444 return Text.str(); 445 } 446 344 447 345 448 // Checks if service contents indicates not available … … 355 458 (memcmp(Item->getData(), NO_LINK, Item->getSize()) == 0)); 356 459 } 460 461 462 // Tokenize std::string using given delimeter list 463 vector<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 357 483 358 484 /////////////////////////// -
Evidence/Evidence.h
r224 r229 5 5 #include <stdarg.h> 6 6 #include <string> 7 #include <sstream> 8 #include <iomanip> 7 9 #include <errno.h> 8 10 #include <vector> 11 #include <map> 12 9 13 #include <exception> 10 14 #include <cxxabi.h> … … 17 21 #define EVIDENCE_REVISION "$Revision$" 18 22 23 19 24 // Class declation of Evidence server 20 25 class EvidenceServer: public DimServer { 21 26 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 28 43 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(); 39 46 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(); 49 52 }; 50 51 private:52 53 struct ConfigItem {54 std::string Name;55 char *Value;56 int Time;57 };58 std::vector<struct ConfigItem> ConfigList;59 53 60 54 struct Message { … … 63 57 }; 64 58 65 std::string ServerName;59 std::string Name; 66 60 DimService *MessageService; 67 61 struct Message *MessageData; 68 class Config Update *ModifyInfo;62 class Config *ConfClass; 69 63 70 64 static void SignalHandler(int); // static for signal() … … 72 66 void errorHandler(int, int, char *); 73 67 void exitHandler(int); 74 68 virtual void ConfigChanged() {}; 69 75 70 public: 76 71 EvidenceServer(const char *); … … 81 76 void Message(MessageType, const char *, ...); 82 77 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 *); 85 80 static bool ServiceOK(DimInfo *); 86 81 static bool ServiceOK(DimRpcInfo *); 82 static std::vector<std::string> Tokenize(const std::string &, const std::string & = " "); 87 83 88 84 bool ExitRequest; -
Evidence/History.cc
r224 r229 23 23 24 24 #include <string> 25 #include <vector> 25 #include <sstream> 26 #include <map> 26 27 #include <math.h> 27 28 #include <float.h> 28 29 #include <sys/stat.h> 30 #include <sys/time.h> 29 31 30 32 using namespace std; … … 43 45 string Format; 44 46 }; 45 vector<struct Item> List;47 map<string, struct Item> Map; 46 48 47 49 DimInfo *ServerList; 48 50 char *Directory; 49 char *Change;51 string Change; 50 52 51 53 void infoHandler(); … … 67 69 Directory(Dir) { 68 70 69 // Listof minimum required change for addition to history buffer71 // Map of minimum required change for addition to history buffer 70 72 Change = GetConfig("minchange", " "); 71 73 … … 79 81 80 82 delete ServerList; 81 while ( List.size() != 0) RemoveService(List[0].DataItem->getName());83 while (Map.size() != 0) RemoveService((*Map.begin()).first); 82 84 } 83 85 … … 106 108 // If service is SERVICE_LIST, scan and subscribe/unsubscribe to services 107 109 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 108 119 char *Type, *Name = strtok(I->getString(), "+-!|"); 109 120 while (Name != NULL) { … … 124 135 // ====== Part B: Handle history service === 125 136 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 134 142 // 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 addindto history140 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) { 141 149 // 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 } 150 156 151 157 // 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; 154 160 } 155 161 156 162 // 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; 160 166 void *WrapPos = NULL; 161 char *Buffer = & List[Service].Buffer[0];167 char *Buffer = &Map[Service].Buffer[0]; 162 168 int Oldest = *(int *) Buffer; 163 169 164 170 // 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()) { 166 172 WrapPos = Buffer + Next; 167 173 Next = sizeof(int); … … 199 205 memcpy(Buffer + Next, &EvidenceHistory::EndMark, sizeof(EvidenceHistory::EndMark)); 200 206 201 List[Service].Next = Next;207 Map[Service].Next = Next; 202 208 } 203 209 … … 206 212 void History::rpcHandler() { 207 213 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; 219 224 } 220 225 221 226 // Try to open history file if not found in memory 222 FILE *File = OpenFile( getString(), "rb");227 FILE *File = OpenFile(Name, "rb"); 223 228 if (File == NULL) { 224 229 setData(NULL, 0); … … 232 237 fseek(File, sizeof(int), SEEK_SET); // Skip 'Next' pointer 233 238 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); 235 240 setData(NULL, 0); // Default response 236 241 } … … 239 244 } 240 245 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); 242 247 } 243 248 … … 248 253 void History::AddService(string Name, const char *Format) { 249 254 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 259 263 // 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); 264 266 265 267 // Load history buffer from file if existing … … 270 272 271 273 // 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); 273 275 274 276 // Read next pointer 275 fread(& New.Next, sizeof(New.Next), 1, File);277 fread(&Map[Name].Next, sizeof(Map[Name].Next), 1, File); 276 278 // Skip format string 277 279 while (fgetc(File) != 0 && feof(File) == 0) {} 278 280 // Read buffer 279 fread(& New.Buffer[0], sizeof(char), Size, File);281 fread(&Map[Name].Buffer[0], sizeof(char), Size, File); 280 282 281 283 if (ferror(File) != 0) { 282 284 Message(WARN, "Error reading history file '%s' in AddService()", Name.c_str()); 283 New.Buffer.clear();285 Map[Name].Buffer.clear(); 284 286 } 285 287 if (fclose(File) != 0) Message(WARN, "Error closing history file '%s' in AddService()", Name.c_str());; … … 287 289 288 290 // 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; 294 296 } 295 297 296 298 // 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); 300 300 } 301 301 … … 306 306 void History::RemoveService(string Name) { 307 307 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); 331 330 } 332 331 … … 377 376 378 377 // Sleep until signal caught 379 pause();380 } 378 while (!Hist.ExitRequest) pause(); 379 } -
Evidence/readme.txt
r227 r229 20 20 to run. 21 21 22 - Oliver Grimm, 18/1/201023 22 24 23 Version history … … 44 43 service for each observed server SERVERNAME/AlarmLevel contains the highest 45 44 level that occurred in the past. Reset of alarm level only via a DIM command. 45 19/6/2010 ToString() now returns std::string 46 23/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(). 50 24/6/2010 Workaround for erroneous /SERVICE_LIST updates. Added static tokenize method to 51 Evidence class. 46 52 47 53
Note:
See TracChangeset
for help on using the changeset viewer.