/********************************************************************\ General code to start a server of the Evidence Control System - The server is started with the given name. - DIM exit and error handlers are implemented. - The Status service is published (special format, see below). It can be updated with the State() method. The text will also be logged. - If the severity of a State() call is FATAL, exit() will be called (with this severity, the call to State() is guranteed not to return). - Configuration data can be requested by GetConfig(). - Signal handlers to ignore common signals are installed. These signals will then cause pause() to return which can be used by the application to terminate gracefully. - The static method ToString() converts the contents of a DIMInfo service into text All memory allocated by the non-static methods will be freed by the class destructor. Oliver Grimm, December 2009 \********************************************************************/ #include "Evidence.h" EvidenceServer *ThisServer; // Constructor starts server with given name EvidenceServer::EvidenceServer(const char *Name) { // Initialize Status = NULL; ExitRequest = false; ThisServer = this; // Catch some signals signal(SIGQUIT, &SignalHandler); // CTRL-Backspace signal(SIGTERM, &SignalHandler); // Termination signal signal(SIGINT, &SignalHandler); // CTRL-C signal(SIGHUP, &SignalHandler); // Terminal closed // Catch C++ unhandled exceptions set_terminate(Terminate); // Start server static char Init[] = "Server started"; Status = new DimService((string(Name) + "/Status").c_str(), (char *) "C", Init, sizeof(Init)); start(Name); addExitHandler(this); } // Destructor: Free memory EvidenceServer::~EvidenceServer() { for (unsigned int i=0; igetName(), StateString[Severity], Tmp); // Create string with severity encoding snprintf(SBuf, sizeof(SBuf), "%s**", Tmp); SBuf[strlen(SBuf)-2] = '\0'; SBuf[strlen(SBuf)+1] = Severity; if (Tmp != ErrorString) free(Tmp); // Send message to console and log file printf("%s\n", TBuf); if (Severity != INFO) DimClient::sendCommand("DColl/Log", TBuf); // Update DIM status service (including severity encoding) if (Status != NULL) Status->updateService(SBuf, strlen(SBuf)+2); // Terminate if message type is fatal if (Severity == FATAL) exit(EXIT_FAILURE); } // Get configuration data (program terminates if data is missing) // // The memory allocated by all calls to this function will be freed by // the destructor. char* EvidenceServer::GetConfig(const char *Item, const char *Default) { // Determine configuration file update time DimCurrentInfo ModifyTime("Config/ModifyTime", 0); int Time = ModifyTime.getInt(), ItemNo = -1; // Check if configuration request already in list for (unsigned int i=0; i= Time) return ConfigList[i].Value; // Otherwise, free memory of old value delete[] ConfigList[i].Name; delete[] ConfigList[i].Value; ItemNo = i; break; } } // Make configuration request DimRpcInfo Config((char *) "ConfigRequest", (char *) ""); Config.setData((char *) Item); char *Result = Config.getString(); // Terminate if not successful if (strlen(Result) == 0) { if (Default == NULL) State(FATAL, "Missing configuration data '%s'", Item); Result = (char *) Default; } // Enlarge list if necessary if (ItemNo == -1) { struct ConfigItem New; ConfigList.push_back(New); ItemNo = ConfigList.size()-1; } // Create new entry in item list, allocate memory and copy data to this memory ConfigList[ItemNo].Value = new char [strlen(Result)+1]; ConfigList[ItemNo].Name = new char [strlen(Item)+1]; strcpy(ConfigList[ItemNo].Name, Item); strcpy(ConfigList[ItemNo].Value, Result); ConfigList[ItemNo].Time = Time; // Return address to configuration value return ConfigList[ItemNo].Value; } // ====== Static methods ====== // Signal handler (causes pause() and other syscalls to return) void EvidenceServer::SignalHandler(int) { ThisServer->ExitRequest = true; } // C++ exception handler void EvidenceServer::Terminate() { string Msg = string(ThisServer->Status->getName()) + ": Caught unhandled exception"; printf("%s\n", Msg.c_str()); DimClient::sendCommand("DColl/Log", Msg.c_str()); abort(); } // Translates DIMInfo to string (memory has to be freed by caller) // No DIM structures are supported (only a single number or string is converted) // For string conversion, a terminating \0 is enforced. char *EvidenceServer::ToString(DimInfo *Item) { char *Text; int R; if (strlen(Item->getFormat()) != 1) return NULL; switch (*(Item->getFormat())) { case 'I': R = asprintf(&Text, "%d", Item->getInt()); break; case 'S': R = asprintf(&Text, "%hd", Item->getShort()); break; case 'F': R = asprintf(&Text, "%.5f", Item->getFloat()); break; case 'D': R = asprintf(&Text, "%.5f", Item->getDouble()); break; case 'X': R = asprintf(&Text, "%lld", Item->getLonglong()); break; case 'C': *(Item->getString() + Item->getSize()) = '\0'; R = asprintf(&Text, "%s", Item->getString()); break; default: return NULL; } return (R == -1) ? NULL : Text; }