Changeset 262 for Evidence/Evidence.cc
- Timestamp:
- 07/26/10 17:53:31 (14 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
Evidence/Evidence.cc
r255 r262 31 31 // 32 32 33 // Constructor 34 EvidenceServer::Config::Config( string Name): DimRpcInfo("ConfigRequest", NO_LINK), Name(Name) {35 36 // Initialise 33 // Constructor: Subscribe to be informed on configuration file change 34 EvidenceServer::Config::Config(): DimRpcInfo("ConfigRequest", NO_LINK), 35 DimCommand((This->Name+"/ResetMessage").c_str(), (char *) "") { 36 37 37 CurrentItem = string(); 38 38 ConfigTimeStamp = 0; 39 ThreadID = pthread_self();40 41 // Subscribe to be informed on configuration file change42 39 Service = new DimInfo("Config/ModifyTime", NO_LINK, this); 43 40 } … … 49 46 } 50 47 48 // Reset message and severity 49 void EvidenceServer::Config::commandHandler() { 50 51 This->Message(INFO, "Message reset by %s (ID %d)", getClientName(), getClientId()); 52 } 53 51 54 // Track last modification time of configuration file 52 55 void EvidenceServer::Config::infoHandler() { 53 56 57 pthread_t Thread; 58 int Ret; 59 60 if (!ServiceOK(DimInfo::getInfo())) return; 61 return; 54 62 This->Lock(); 55 63 ConfigTimeStamp = getInfo()->getInt(); 56 64 This->Unlock(); 57 65 58 if (pthread_kill(ThreadID, This->ConfigSignal) != 0) { 59 This->Message(WARN, "Could not send signal to main thread"); 60 } 61 } 62 63 // Receive answer to remote procedure call 66 // Launch ConfigChanged() as detached thread 67 if ((Ret = pthread_create(&Thread, NULL, (void * (*)(void *)) EvidenceServer::CallConfigChanged, (void *) NULL)) != 0) { 68 This->Message(ERROR, "pthread_create() failed in EvidenceServer::Config::infoHandler() (%s)\n", strerror(Ret)); 69 } 70 else if ((Ret = pthread_detach(Thread)) != 0) { 71 This->Message(ERROR, "pthread_detach() failed in EvidenceServer::Config::infoHandler() (%s)\n", strerror(Ret)); 72 } 73 } 74 75 // Answer to remote procedure call: Update map 64 76 void EvidenceServer::Config::rpcInfoHandler(){ 65 77 66 78 This->Lock(); 67 // Update map68 List[CurrentItem].Value = string(getString(), getSize()-1);69 List[CurrentItem].Time = ConfigTimeStamp; 79 This->List[CurrentItem].Value = string(DimRpcInfo::getString(), DimRpcInfo::getSize()-1); 80 This->List[CurrentItem].Time = ConfigTimeStamp; 81 70 82 // Clear to allow new rpc call 71 83 CurrentItem.clear(); … … 73 85 } 74 86 75 // Return configuration data if still up to date or empty string otherwise 76 string EvidenceServer::Config::GetConfig(string Item, string Default) { 87 // Request configuration data possible only when answer to previous request received 88 string EvidenceServer::Config::RequestNB(string Item) { 89 90 This->Lock(); 91 if (CurrentItem.empty()) { 92 CurrentItem = Item; 93 setData(((char *) Item.c_str())); 94 } 95 This->Unlock(); 96 } 97 98 99 ////////////////////////// 100 // EvidenceServer Class // 101 ////////////////////////// 102 103 // Initialise 104 EvidenceServer *EvidenceServer::This = NULL; 105 pthread_mutex_t EvidenceServer::Mutex; 106 set<pthread_t> EvidenceServer::Threads; 107 108 109 // Constructor 110 EvidenceServer::EvidenceServer(string ServerName): Name(ServerName) { 111 112 // Initialize 113 MessageService = NULL; 114 MessageData = NULL; 115 ExitRequest = false; 116 This = this; 117 Threads.insert(pthread_self()); 118 119 // Initialise mutex 120 int Ret; 121 pthread_mutexattr_t Attr; 122 123 if ((Ret = pthread_mutexattr_settype(&Attr, PTHREAD_MUTEX_ERRORCHECK)) != 0) { 124 Message(FATAL, "pthread_mutex_settype() failed (%s)", strerror(Ret)); 125 } 126 if ((Ret = pthread_mutex_init(&Mutex, &Attr)) != 0) { 127 Message(FATAL, "pthread_mutex_init() failed (%s)", strerror(Ret)); 128 } 129 130 // Catch some signals 131 signal(SIGQUIT, &SignalHandler); // CTRL-Backspace 132 signal(SIGTERM, &SignalHandler); // Termination signal 133 signal(SIGINT, &SignalHandler); // CTRL-C 134 signal(SIGHUP, &SignalHandler); // Terminal closed 135 136 // Catch C++ unhandled exceptions 137 set_terminate(Terminate); 138 139 // Message service and initial message 140 MessageService = new DimService((Name+"/Message").c_str(), (char *) "I:1;C", NULL, 0); 141 142 string Rev(EVIDENCE_REVISION); 143 Message(INFO, "Server started (%s, compiled %s %s)", (Rev.substr(1, Rev.size()-3)).c_str(),__DATE__, __TIME__); 144 145 // Configuration class 146 ConfClass = new class Config(); 147 148 // Start server 149 start(ServerName.c_str()); 150 addExitHandler(this); 151 } 152 153 154 // Destructor: Free memory 155 EvidenceServer::~EvidenceServer() { 156 157 Message(INFO, "Server stopped"); 158 159 delete ConfClass; 160 161 int Ret; 162 if ((Ret = pthread_mutex_destroy(&Mutex)) != 0) { 163 Message(ERROR, "pthread_mutex_destroy() failed (%s)", strerror(Ret)); 164 } 165 166 delete MessageService; 167 delete[] MessageData; 168 } 169 170 171 // DIM exit handler 172 void EvidenceServer::exitHandler(int Code) { 173 174 Message(INFO, "Exit handler called (DIM exit code %d)", Code); 175 exit(EXIT_SUCCESS); 176 } 177 178 // DIM error handler 179 void EvidenceServer::errorHandler(int Severity, int Code, char *Text) { 180 181 Message(ERROR, "%s (DIM error code %d, DIM severity %d)\n", Text, Code, Severity); 182 } 183 184 185 // Set server message (if Severity is FATAL, exit() will be invoked) 186 void EvidenceServer::Message(MessageType Severity, const char *Format, ...) { 187 188 static const char* StateString[] = {"Info", "Warn", "Error", "Fatal"}; 189 static char ErrorString[] = "vasprintf() failed in Message()"; 190 char *Text; 191 192 // Assemble message from application 193 va_list ArgumentPointer; 194 va_start(ArgumentPointer, Format); 195 if (vasprintf(&Text, Format, ArgumentPointer) == -1) { 196 Text = ErrorString; 197 Severity = ERROR; 198 } 199 va_end(ArgumentPointer); 200 201 // Generate new Message structure and free text 202 struct Message *NewMsg = (struct Message *) new char [sizeof(struct Message)+strlen(Text)+1]; 203 NewMsg->Severity = Severity; 204 strcpy(NewMsg->Text, Text); 205 if (Text != ErrorString) free(Text); 206 207 // Send message to console and log file 208 printf("%s (%s): %s\n", MessageService->getName(), StateString[Severity], NewMsg->Text); 209 SendToLog("%s (%s): %s", MessageService->getName(), StateString[Severity], NewMsg->Text); 210 211 // Update DIM message service 212 if (MessageService != NULL) { 213 MessageService->updateService(NewMsg, sizeof(struct Message)+strlen(NewMsg->Text)+1); 214 } 215 216 // Delete old message 217 Lock(); 218 delete[] MessageData; 219 MessageData = NewMsg; 220 Unlock(); 221 222 // Terminate if severity if FATAL 223 if (Severity == FATAL) exit(EXIT_FAILURE); 224 } 225 226 227 // Send to central logging server with non-blocking command 228 void EvidenceServer::SendToLog(const char *Format, ...) { 229 230 static char ErrorString[] = "vasprintf() failed in SendToLog()"; 231 char *Buffer; 232 int Ret; 233 234 // Evaluate variable argument list 235 va_list ArgumentPointer; 236 va_start(ArgumentPointer, Format); 237 Ret = vasprintf(&Buffer, Format, ArgumentPointer); 238 va_end(ArgumentPointer); 239 240 // Send to logger 241 if (Ret != -1) { 242 DimClient::sendCommandNB("DColl/Log", Buffer); 243 free (Buffer); 244 } 245 else DimClient::sendCommandNB("DColl/Log", ErrorString); 246 } 247 248 249 // Get configuration data 250 // 251 // Program terminates if data is missing and no default given. Actual configuration 252 // request will be made only if config file has modification since last request. 253 // If called from infoHandler(), a non-blocking request will be made 254 string EvidenceServer::GetConfig(string Item, string Default) { 77 255 78 256 string Result; 79 257 bool Blocking = false; 258 80 259 // If up-to-date data in configuration list available, return this 81 This->Lock(); 82 if ((List.count(Item) > 0) && (List[Item].Time >= ConfigTimeStamp)) Result = List[Item].Value; 83 This->Unlock(); 260 Lock(); 261 if ((List.count(Item) > 0) && (List[Item].Time >= ConfClass->ConfigTimeStamp)) Result = List[Item].Value; 262 if (Threads.count(pthread_self()) != 0) Blocking = true; 263 Unlock(); 84 264 if (!Result.empty()) return Result; 85 265 86 // Blocking configuration request if in main thread87 if ( pthread_self() == ThreadID) {266 // Blocking configuration request 267 if (Blocking) { 88 268 DimRpcInfo Config((char *) "ConfigRequest", NO_LINK); 89 269 Config.setData((char *) (Name + " " + Item).c_str()); … … 92 272 if (!EvidenceServer::ServiceOK(&Config)) { 93 273 if (Default.empty()) { 94 This->Message(FATAL, "Configuration server unreachable, can't retrieve '%s'", Item.c_str());274 Message(FATAL, "Configuration server unreachable, can't retrieve '%s'", Item.c_str()); 95 275 } 96 276 else Result = Default; … … 103 283 // Update configuration map 104 284 if (!Result.empty()) { 105 This->Lock();285 Lock(); 106 286 List[Item].Value = Result; 107 List[Item].Time = Conf igTimeStamp;108 This->Unlock();287 List[Item].Time = ConfClass->ConfigTimeStamp; 288 Unlock(); 109 289 } 110 290 } 111 291 112 // Non-blocking configuration request from other threads113 if ( pthread_self() != ThreadID) {114 This->Lock();292 // Non-blocking configuration request 293 if (!Blocking) { 294 Lock(); 115 295 if (List.count(Item) > 0) { 116 // New request possible only when answer to previous request received 117 if (CurrentItem.empty()) { 118 CurrentItem = Item; 119 setData(((char *) (Name + " " + Item).c_str())); 120 } 121 122 // Return current value 296 ConfClass->RequestNB(Name + " " + Item); 123 297 Result = List[Item].Value; 124 298 } 125 This->Unlock(); 126 } 299 Unlock(); 300 } 301 302 // Terminate if no configuration information found 303 if (Result.empty()) Message(FATAL, "Missing configuration data '%s'", Item.c_str()); 127 304 128 305 return Result; … … 130 307 131 308 132 //////////////////////////133 // EvidenceServer Class //134 //////////////////////////135 136 // Initialise137 int EvidenceServer::ConfigSignal = 0;138 EvidenceServer *EvidenceServer::This = NULL;139 140 // Constructor141 EvidenceServer::EvidenceServer(string ServerName): Name(ServerName) {142 143 // Initialize144 MessageService = NULL;145 MessageData = NULL;146 ExitRequest = false;147 This = this;148 149 // Initialise mutex150 int Ret;151 pthread_mutexattr_t Attr;152 153 if ((Ret = pthread_mutexattr_settype(&Attr, PTHREAD_MUTEX_ERRORCHECK)) != 0) {154 Message(FATAL, "pthread_mutex_settype() failed (%s)", strerror(Ret));155 }156 if ((Ret = pthread_mutex_init(&Mutex, &Attr)) != 0) {157 Message(FATAL, "pthread_mutex_init() failed (%s)", strerror(Ret));158 }159 160 // Catch some signals161 signal(SIGQUIT, &SignalHandler); // CTRL-Backspace162 signal(SIGTERM, &SignalHandler); // Termination signal163 signal(SIGINT, &SignalHandler); // CTRL-C164 signal(SIGHUP, &SignalHandler); // Terminal closed165 166 // Catch C++ unhandled exceptions167 set_terminate(Terminate);168 169 // Configuration class (must be instantiate after signal handling installed)170 ConfClass = new class Config(Name);171 172 // Message service and initial message173 MessageService = new DimService((Name+"/Message").c_str(), (char *) "I:1;C", NULL, 0);174 175 string Rev(EVIDENCE_REVISION);176 Message(INFO, "Server started (%s, compiled %s %s)", (Rev.substr(1, Rev.size()-3)).c_str(),__DATE__, __TIME__);177 178 // Start server179 start(ServerName.c_str());180 addExitHandler(this);181 }182 183 // Destructor: Free memory184 EvidenceServer::~EvidenceServer() {185 186 Message(INFO, "Server stopped");187 188 delete ConfClass;189 190 int Ret;191 if ((Ret = pthread_mutex_destroy(&Mutex)) != 0) {192 Message(ERROR, "pthread_mutex_destroy() failed (%s)", strerror(Ret));193 }194 195 delete MessageService;196 delete[] MessageData;197 }198 199 // DIM exit handler200 void EvidenceServer::exitHandler(int Code) {201 202 if (Code == 0) Message(INFO, "Message cleared by %s (ID %d)", getClientName(), getClientId());203 else {204 Message(INFO, "Exit handler called (DIM exit code %d)", Code);205 exit(EXIT_SUCCESS);206 }207 }208 209 // DIM error handler210 void EvidenceServer::errorHandler(int Severity, int Code, char *Text) {211 212 Message(ERROR, "%s (DIM error code %d, DIM severity %d)\n", Text, Code, Severity);213 }214 215 // Set server message (if Severity is FATAL, exit() will be invoked)216 void EvidenceServer::Message(MessageType Severity, const char *Format, ...) {217 218 static const char* StateString[] = {"Info", "Warn", "Error", "Fatal"};219 static char ErrorString[] = "vasprintf() failed in Message()";220 char *Text;221 222 // Assemble message from application223 va_list ArgumentPointer;224 va_start(ArgumentPointer, Format);225 if (vasprintf(&Text, Format, ArgumentPointer) == -1) {226 Text = ErrorString;227 Severity = ERROR;228 }229 va_end(ArgumentPointer);230 231 // Generate new Message structure and free text232 struct Message *NewMsg = (struct Message *) new char [sizeof(struct Message)+strlen(Text)+1];233 NewMsg->Severity = Severity;234 strcpy(NewMsg->Text, Text);235 if (Text != ErrorString) free(Text);236 237 // Send message to console and log file238 printf("%s (%s): %s\n", MessageService->getName(), StateString[Severity], NewMsg->Text);239 SendToLog("%s (%s): %s", MessageService->getName(), StateString[Severity], NewMsg->Text);240 241 // Update DIM message service242 if (MessageService != NULL) {243 MessageService->updateService(NewMsg, sizeof(struct Message)+strlen(NewMsg->Text)+1);244 }245 246 // Delete old message247 Lock();248 delete[] MessageData;249 MessageData = NewMsg;250 Unlock();251 252 // Terminate if severity if FATAL253 if (Severity == FATAL) exit(EXIT_FAILURE);254 }255 256 257 // Send to central logging server with non-blocking command258 void EvidenceServer::SendToLog(const char *Format, ...) {259 260 static char ErrorString[] = "vasprintf() failed in SendToLog()";261 char *Buffer;262 int Ret;263 264 // Evaluate variable argument list265 va_list ArgumentPointer;266 va_start(ArgumentPointer, Format);267 Ret = vasprintf(&Buffer, Format, ArgumentPointer);268 va_end(ArgumentPointer);269 270 // Send to logger271 if (Ret != -1) {272 DimClient::sendCommandNB("DColl/Log", Buffer);273 free (Buffer);274 }275 else DimClient::sendCommandNB("DColl/Log", ErrorString);276 }277 278 279 // Get configuration data280 //281 // Program terminates if data is missing and no default given. Actual configuration282 // request will be made only if config file has modification since last request.283 // If called from infoHandler(), a non-blocking request will be made284 string EvidenceServer::GetConfig(string Item, string Default) {285 286 string Result = ConfClass->GetConfig(Item, Default);287 if (Result.empty()) Message(FATAL, "Missing configuration data '%s'", Item.c_str());288 return Result;289 }290 291 292 // Set signal emitted when configuraton file changes, signal handler calls ConfigChanged()293 void EvidenceServer::ActivateSignal(int Signal) {294 295 struct sigaction S;296 297 ConfigSignal = Signal;298 S.sa_handler = &SignalHandler;299 S.sa_flags = SA_RESTART;300 sigaction(Signal, &S, NULL);301 }302 303 304 309 // Locking and unlocking functions. 305 // Signal blocked before locking (pthread_mutex_lock() not asynch-signal safe).306 310 // Message() is not used to avoid infinite recursion 307 311 void EvidenceServer::Lock() { 308 312 309 313 int Ret; 310 sigset_t Set; 311 312 if (ConfigSignal != 0) { 313 Ret = abs(sigemptyset(&Set)); 314 Ret += abs(sigaddset(&Set, ConfigSignal)); 315 Ret += abs(pthread_sigmask(SIG_BLOCK, &Set, NULL)); 316 317 if (Ret != 0) { 318 printf("Signal masking failed in Lock()"); 319 SendToLog("Signal masking failed in Lock()"); 320 exit(EXIT_FAILURE); 321 } 322 } 323 324 if ((Ret = pthread_mutex_lock(&Mutex)) != 0) { 314 315 if ((Ret = pthread_mutex_lock(&EvidenceServer::Mutex)) != 0) { 325 316 printf("pthread_mutex_lock() failed in Lock() (%s)", strerror(Ret)); 326 317 SendToLog("pthread_mutex_lock() failed in Lock() (%s)", strerror(Ret)); … … 332 323 333 324 int Ret; 334 sigset_t Set; 335 336 if ((Ret = pthread_mutex_unlock(&Mutex)) != 0) { 325 326 if ((Ret = pthread_mutex_unlock(&EvidenceServer::Mutex)) != 0) { 337 327 printf("pthread_mutex_unlock() failed in Unlock() (%s)", strerror(Ret)); 338 328 SendToLog("pthread_mutex_unlock() failed in Unlock() (%s)", strerror(Ret)); 339 329 exit(EXIT_FAILURE); 340 } 341 342 if (ConfigSignal != 0) { 343 Ret = abs(sigemptyset(&Set)); 344 Ret += abs(sigaddset(&Set, ConfigSignal)); 345 Ret += abs(pthread_sigmask(SIG_UNBLOCK, &Set, NULL)); 346 347 if (Ret != 0) { 348 printf("Signal unmasking failed in Unlock()"); 349 SendToLog("Signal unmasking failed in Unlock()"); 350 exit(EXIT_FAILURE); 351 } 352 } 330 } 353 331 } 354 332 355 333 356 334 // ====== Static methods ====== 335 336 // Stub to call ConfigChanged() method of class as separate thread 337 // Thread set is used to determine if blocking or non-blocking rpc is to be used 338 void EvidenceServer::CallConfigChanged() { 339 340 EvidenceServer::Lock(); 341 EvidenceServer::Threads.insert(pthread_self()); 342 EvidenceServer::Unlock(); 343 344 This->ConfigChanged(); 345 346 EvidenceServer::Lock(); 347 EvidenceServer::Threads.erase(pthread_self()); 348 EvidenceServer::Unlock(); 349 } 350 357 351 358 352 // Signal handler (causes pause() and other syscalls to return) … … 360 354 361 355 static bool Called = false; 362 363 // If signal indicates configuration change, invoke call-back364 if (Signal == EvidenceServer::ConfigSignal) {365 This->ConfigChanged();366 return;367 }368 356 369 357 // At first invocation just request exit … … 378 366 exit(EXIT_FAILURE); 379 367 } 368 380 369 381 370 // C++ exception handler (derived from gcc __verbose_terminate_handler()) … … 492 481 } 493 482 483 bool EvidenceServer::ServiceOK(DimCurrentInfo *Item) { 484 485 return !((Item->getSize() == strlen(NO_LINK)+1) && 486 (memcmp(Item->getData(), NO_LINK, Item->getSize()) == 0)); 487 } 488 494 489 495 490 // Tokenize std::string using given delimeter list
Note:
See TracChangeset
for help on using the changeset viewer.