/********************************************************************\ 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. It can be updated with the Msg() method. The text will also be logged. - 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; MsgBuffer = 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 (asprintf(&ServerName, "%s/Status", Name) == -1) { ServerName = NULL; Msg(FATAL, "Could not generate service name, asprintf() failed"); } // Start server static char InitMsg[] = "OK" "\0" "0"; Status = new DimService(ServerName, (char *) "C", InitMsg, sizeof(InitMsg)); DimServer::start(Name); DimServer::addExitHandler(this); Msg(INFO, "Server started"); } // Destructor: Frees all buffers EvidenceServer::~EvidenceServer() { free(ServerName); free(MsgBuffer); for (unsigned int i=0; iupdateService(MsgBuffer, Size+1); // 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) { // Enlarge memory to hold new pointer DimRpcInfo **Config = (DimRpcInfo **) realloc(ConfigList, sizeof(void *) * (++ConfigNum)); if (Config == NULL) { Msg(WARN, "Could not realloc() memory for DimRpcInfo list (%s)", strerror(errno)); ConfigNum--; } else ConfigList = (void *) Config; // Advance array pointer to position for new DimRpcInfo pointer Config += ConfigNum - 1; // Make configuration request *Config = new DimRpcInfo((char *) "ConfigRequest", (char *) ""); (*Config)->setData((char *) Item); // Terminate if not successful if (strlen((*Config)->getString()) == 0) { Msg(FATAL, "Missing configuration data '%s'", Item); } return (*Config)->getString(); } // ====== Static methods ====== // Signal handler (causes pause() to return) void EvidenceServer::SignalHandler(int) { EvidenceServer::ExitRequest = true; } // Translates DIMInfo to string (memory has to be freed by caller) char *EvidenceServer::ToString(DimInfo *Item) { char *Text; int R; // Cannot handle complex data formats if (strlen(Item->getFormat()) != 1) return NULL; // Interpret format switch (*(Item->getFormat())) { case 'I': R = asprintf(&Text, "%d", Item->getInt()); break; case 'C': R = asprintf(&Text, "%s", Item->getString()); break; case 'S': R = asprintf(&Text, "%hd", Item->getShort()); break; case 'F': R = asprintf(&Text, "%.3f", Item->getFloat()); break; case 'D': R = asprintf(&Text, "%.3f", Item->getDouble()); break; case 'X': R = asprintf(&Text, "%lld", Item->getLonglong()); break; default: return NULL; } // Check if aprintf() worked OK if (R != -1) return Text; else return NULL; }