/********************************************************************\ Configuration server for the Evidence Control System - The configuration file is opened without buffering to catch changes without closing/opening. - If a configuration file change is detected through inotify, the service "Config/Modified" is updated (it contains no data) to inform applications. - The employed line buffer has conservatively at least the size of the configuration file. If needed, it will be enlarged. Oliver Grimm, November 2009 \********************************************************************/ #define CONFIG_FILE "configuration.txt" #define SERVER_NAME "Config" #include "../Evidence.h" #include #include // // Class derived from DimRpc // class EvidenceConfig: public DimRpc, public EvidenceServer { private: FILE *File; char *Buffer; unsigned int BufferLength; DimService *ConfigModified; void rpcHandler(); public: EvidenceConfig(const char *); ~EvidenceConfig(); void ConfigChanged(); }; // Constructor EvidenceConfig::EvidenceConfig(const char *Filename): DimRpc("ConfigRequest", "C", "C"), EvidenceServer(SERVER_NAME) { // Create DIM service to indicate changes of configuration file ConfigModified = new DimService (SERVER_NAME"/Modified", (char *) ""); // Open configuration file if ((File = fopen(Filename, "r")) == NULL) { Msg(FATAL, "Could not open configuration file '%s' (%s)\n", Filename, strerror(errno)); } // Disable buffering, so file modifications are immediately seen if(setvbuf(File, NULL, _IONBF, 0) != 0) { Msg(WARN, "Error setting configuration file '%s' to unbuffered mode.\n", Filename); } Buffer = NULL; // Will be allocated in rpcHandler() BufferLength = 0; } // Destructor EvidenceConfig::~EvidenceConfig() { if (File != NULL) fclose(File); delete[] Buffer; } // Implementation of response to configuration request void EvidenceConfig::rpcHandler() { char *Token1,*Token2,*Token3, *Request = getString(); struct stat FileStatus; // Check if Buffer[] is large enough to hold full file, enlarge if necessary if (fstat(fileno(File), &FileStatus) == -1) { Msg(ERROR, "Could not determine size of configuration file to allocate buffer (%s)\n", strerror(errno)); } else if(BufferLength < FileStatus.st_size) { delete[] Buffer; Buffer = new char [FileStatus.st_size]; BufferLength = FileStatus.st_size; } // Search for configuration item rewind(File); while (fgets(Buffer, BufferLength, File) != NULL) { // Combine lines that end with '+' while (Buffer[strlen(Buffer)-2] == '+') { if (fgets(Buffer+strlen(Buffer)-2, BufferLength-(strlen(Buffer)-2), File) == NULL) break; } // Ignore comments for (int i=0; iupdateService(); } // // Declaring class static ensures destructor is called when exit() is invoked // int main() { static EvidenceConfig Config(CONFIG_FILE); int Notify; struct inotify_event Event; if ((Notify = inotify_init()) == -1) { Config.Msg(EvidenceConfig::WARN, "inotify_init() failed, cannot monitor changes of configuration file (%s)\n", strerror(errno)); } else if (inotify_add_watch(Notify, CONFIG_FILE, IN_MODIFY) == -1) { Config.Msg(EvidenceConfig::WARN, "Could not set inotify watch on configuration file (%s)\n", strerror(errno)); close(Notify); Notify = -1; } // Sleep until file changes or signal caught while (!EvidenceServer::ExitRequest) { if (Notify != -1) { read(Notify, &Event, sizeof(Event)); Config.ConfigChanged(); } else pause(); } if (Notify != -1) close(Notify); }