/********************************************************************\ 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" bool EvidenceServer::ExitRequest = false; // Constructor starts server with given name EvidenceServer::EvidenceServer(const char *Name) { // Initialize Status = NULL; ConfigList = NULL; ConfigNum = 0; // Catch some signals signal(SIGQUIT, &SignalHandler); // CTRL-Backspace signal(SIGTERM, &SignalHandler); // Termination signal signal(SIGINT, &SignalHandler); // CTRL-C signal(SIGHUP, &SignalHandler); // Terminal closed // Create server name if (MakeString(&StatusName, "%s/Status", Name) == -1) { State(FATAL, "Could not generate service name, asprintf() failed"); } // Start server Status = new DimService(StatusName, (char *) "Server started"); start(Name); addExitHandler(this); } // Destructor: Free memory EvidenceServer::~EvidenceServer() { free(StatusName); for (unsigned int i=0; iupdateService(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) { // 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); // Terminate if not successful if (strlen(Config.getString()) == 0) { State(FATAL, "Missing configuration data '%s'", Item); } // Enlarge memory to hold new pointer if necessary if (ItemNo == -1) { void *N = realloc(ConfigList, sizeof(struct ConfigItem)*(++ConfigNum)); if (N == NULL) { State(WARN, "Could not realloc() memory for configuration, will lose memory (%s)", strerror(errno)); ConfigNum--; } else ConfigList = (struct ConfigItem *) N; ItemNo = ConfigNum-1; } // Allocate memory for strings, and copy data to this memory ConfigList[ItemNo].Value = new char [strlen(Config.getString())+1]; ConfigList[ItemNo].Name = new char [strlen(Item)+1]; strcpy(ConfigList[ItemNo].Name, Item); strcpy(ConfigList[ItemNo].Value, Config.getString()); 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) { EvidenceServer::ExitRequest = true; } // Translates DIMInfo to string (memory has to be freed by caller) // No DIM structures are supported (only a single number or string is converted) char *EvidenceServer::ToString(DimInfo *Item) { char *Text; if (strlen(Item->getFormat()) != 1) return NULL; switch (*(Item->getFormat())) { case 'I': MakeString(&Text, "%d", Item->getInt()); break; case 'C': MakeString(&Text, "%s", Item->getString()); break; case 'S': MakeString(&Text, "%hd", Item->getShort()); break; case 'F': MakeString(&Text, "%.5f", Item->getFloat()); break; case 'D': MakeString(&Text, "%.5f", Item->getDouble()); break; case 'X': MakeString(&Text, "%lld", Item->getLonglong()); break; default: return NULL; } return Text; } // // Generate string with vasprintf() // // The pointer will be set to NULL in case of error, so can always safely passed to free(). // In case vasprintf() is not available on a particular system, the functionality can // be manually implemented in this routine. // int EvidenceServer::MakeString(char **Pointer, const char *Format, ...) { int Ret; va_list ArgumentPointer; va_start(ArgumentPointer, Format); if ((Ret = vasprintf(Pointer, Format, ArgumentPointer)) == -1) Pointer = NULL; va_end(ArgumentPointer); return Ret; }