Changeset 203
Legend:
- Unmodified
- Added
- Removed
-
Evidence/Config.cc
r187 r203 3 3 Configuration server for the Evidence Control System 4 4 5 - The configuration file is opened without buffering to catch changes6 without closing/opening.7 5 - The name of a configuration file can be given as command line argument 8 6 - If a configuration file change is detected through inotify, the service 9 "Config/ModifyTime" is updated with the current UNIX time to inform applications. 10 The initial value of the server is the last file modification time. 11 - The employed line buffer has conservatively at least the size of the 12 configuration file. If needed, it will be enlarged. 7 "Config/ModifyTime" contains the last modification UNIX time. 8 - The contents of the configuration file is available through Config/ConfigData. 9 - The current parser removes all tabs, multiple, leading and trailing spaces, and 10 concatenates lines ending with '+'. 11 12 A mutex is used for preventing concurrent access to the configuration data from 13 the methods rpcHandler() and ConfigChanged(). 13 14 14 Oliver Grimm, November 200915 Oliver Grimm, April 2010 15 16 16 17 \********************************************************************/ … … 24 25 #include <sys/stat.h> 25 26 #include <sys/inotify.h> 27 #include <sstream> 28 29 using namespace std; 26 30 27 31 // … … 31 35 32 36 private: 37 struct Item { 38 string Name; 39 string Data; 40 }; 41 vector<struct Item> List; 42 33 43 FILE *File; 34 char *Buffer; 35 unsigned int BufferLength; 44 char *FileContent; 36 45 DimService *ConfigModified; 37 int ModifyTime; 46 DimService *ConfigContent; 47 pthread_mutex_t Mutex; 38 48 39 49 void rpcHandler(); … … 51 61 DimRpc("ConfigRequest", "C", "C"), EvidenceServer(SERVER_NAME) { 52 62 63 ConfigModified = NULL; // Will be allocated in ConfigChanged() 64 ConfigContent = NULL; 65 FileContent = NULL; 66 67 // Initialise mutex (errno is not set by pthread_mutex_init()) 68 if (pthread_mutex_init(&Mutex, NULL) != 0) { 69 State(FATAL, "pthread_mutex_init() failed"); 70 } 71 53 72 // Open configuration file 54 73 if ((File = fopen(Filename, "r")) == NULL) { … … 56 75 } 57 76 58 // Create DIM service to indicate changes of configuration file59 struct stat Stat;60 if (stat(Filename, &Stat) == -1) {61 State(WARN, "Could not read last modification time of configuration file '%s' (%s)", Filename, strerror(errno));62 ModifyTime = 0;63 }64 else ModifyTime = Stat.st_mtime;65 ConfigModified = new DimService (SERVER_NAME"/ModifyTime", ModifyTime);66 67 77 // Disable buffering, so file modifications are immediately seen 68 78 if (setvbuf(File, NULL, _IONBF, 0) != 0) { 69 79 State(WARN, "Error setting configuration file '%s' to unbuffered mode", Filename); 70 80 } 71 72 Buffer = NULL; // Will be allocated in rpcHandler()73 BufferLength = 0;81 82 // Create DIM services 83 ConfigChanged(); 74 84 } 75 85 … … 77 87 EvidenceConfig::~EvidenceConfig() { 78 88 79 if (File != NULL) fclose(File); 80 delete[] Buffer; 81 } 89 if (File != NULL && fclose(File) != 0) State(ERROR, "Error closing configuration file (%s)", strerror(errno)); 90 91 delete ConfigModified; 92 delete ConfigContent; 93 delete[] FileContent; 94 95 if (pthread_mutex_destroy(&Mutex) != 0) State(ERROR, "pthread_mutex_destroy() failed"); 96 } 97 82 98 83 99 // Implementation of response to configuration request 84 100 void EvidenceConfig::rpcHandler() { 85 101 86 char *Token1,*Token2,*Token3, *Request = getString(); 87 struct stat FileStatus; 88 89 // Check if Buffer[] is large enough to hold full file, enlarge if necessary 90 if (fstat(fileno(File), &FileStatus) == -1) { 91 State(FATAL, "Could not determine size of configuration file to allocate buffer (%s)", strerror(errno)); 92 } 93 else if(BufferLength < FileStatus.st_size) { 94 delete[] Buffer; 95 Buffer = new char [FileStatus.st_size]; 96 BufferLength = FileStatus.st_size; 97 } 98 99 // Search for configuration item 100 rewind(File); 101 while (fgets(Buffer, BufferLength, File) != NULL) { 102 string Response; 103 104 // Lock because ConfigChange() might access concurrently 105 if (pthread_mutex_lock(&Mutex) != 0) State(ERROR, "pthread_mutex_lock() failed in rpcHandler()"); 106 107 // Search for config data in list 108 for (int i=0; i<List.size(); i++) { 109 if (List[i].Name == getString()) Response = List[i].Data; 110 } 111 112 // Unlock 113 if (pthread_mutex_unlock(&Mutex) != 0) State(ERROR, "pthread_mutex_unlock() failed in rpcHandler()"); 114 115 // Send data and update Status 116 setData((char *) Response.c_str()); 102 117 103 // Combine lines that end with '+'104 while (Buffer[strlen(Buffer)-2] == '+') {105 if (fgets(Buffer+strlen(Buffer)-2, BufferLength-(strlen(Buffer)-2), File) == NULL) break;106 }107 108 // Ignore comments109 for (int i=0; i<strlen(Buffer); i++) if (Buffer[i] == '#') Buffer[i] = '\0';110 111 // Extract tokens112 Token1 = strtok(Buffer, " \t:");113 Token2 = strtok(NULL, " \t:");114 Token3 = strtok(NULL, "\n");115 116 // Check if all tokens existing117 if(Token1==NULL || Token2==NULL || Token3==NULL) continue;118 119 // Check for match and then send data (removing whitespace and both ends)120 if (strstr(Request, Token1)!=NULL && strstr(Request, Token2)!=NULL) {121 while (isspace(*Token3) != 0) Token3++;122 while ((strlen(Token3)>0) && isspace(*(Token3+strlen(Token3)-1))) *(Token3+strlen(Token3)-1) = '\0';123 setData(Token3);124 break;125 }126 }127 128 // If configuration data not found, send empty string129 if (feof(File)!=0) setData((char *) "");130 131 118 State(INFO, "Client '%s' (ID %d) requested '%s'. Send '%s'.", 132 119 DimServer::getClientName(), 133 120 DimServer::getClientId(), 134 Request, feof(File)!=0 ? "n/a" : Token3); 135 } 121 getString(), Response.c_str()); 122 } 123 136 124 137 125 // Signalisation of configuration change 138 126 void EvidenceConfig::ConfigChanged() { 139 127 140 ModifyTime = time(NULL); 141 ConfigModified->updateService(); 142 } 128 static int ModifyTime; 129 130 // 131 // Part A: Handle updates to DIM services 132 // 133 134 // Access status information for configuration file (if fileno() returns -1, fstat() reports error) 135 struct stat Stat; 136 if (fstat(fileno(File), &Stat) == -1) { 137 State(ERROR, "Error with stat() system call for configuration file, cannot update configuration file information (%s)", strerror(errno)); 138 delete ConfigModified; 139 delete ConfigContent; 140 ConfigModified = NULL; 141 ConfigContent = NULL; 142 return; 143 } 144 145 // Create/update DIM service to indicate changes of configuration file 146 ModifyTime = Stat.st_mtime; 147 if (ConfigModified == NULL) ConfigModified = new DimService (SERVER_NAME"/ModifyTime", ModifyTime); 148 else ConfigModified->updateService(); 149 150 // Read new configuration file (enfore \0 termination) 151 char *NewContent = new char [Stat.st_size+1]; 152 rewind(File); 153 if (fread(NewContent, sizeof(char), Stat.st_size, File) != Stat.st_size) { 154 State(FATAL, "Could not read configuration file"); 155 } 156 NewContent[Stat.st_size] = '\0'; 157 158 // Create/update DIM service that contains the current configuration file 159 if (ConfigContent == NULL )ConfigContent = new DimService(SERVER_NAME"/ConfigData", NewContent); 160 else ConfigContent->updateService(NewContent); 161 162 delete[] FileContent; 163 FileContent = NewContent; 164 165 // 166 // Part B: Interpret configuration list 167 // 168 169 stringstream In(FileContent), Out; 170 string Line; 171 struct Item New; 172 size_t Pos; 173 174 // First clean up and concatenate lines 175 while (getline(In, Line).good()) { 176 // Remove comments 177 if (Line.find('#') != string::npos) Line.erase(Line.find('#')); 178 // Repace all tabs by spaces 179 while (Line.find("\t") != string::npos) Line[Line.find("\t")] = ' '; 180 // Remove leading spaces 181 while (!Line.empty() && isspace(Line[0])) Line.erase(0, 1); 182 // Remove trailing spaces 183 while (!Line.empty() && isspace(Line[Line.size()-1])) Line.erase(Line.size()-1); 184 // Remove empty lines 185 if (Line.empty()) continue; 186 // Concatenate if line ends with '+' 187 if (Line[Line.size()-1] != '+') Out << Line << endl; 188 else Out << Line.erase(Line.size()-1); 189 }; 190 191 In.str(Out.str()); 192 In.clear(); 193 194 // Interpret data 195 while (getline(In, Line).good()) { 196 // Remove multiple spaces 197 while (Line.find(" ") != string::npos) Line.erase(Line.find(" "), 1); 198 199 // Find second space character 200 Pos = Line.find(" ", Line.find(" ") + 1); 201 if(Pos == string::npos) continue; 202 203 // Extract configuration name and data 204 New.Name = string(Line, 0, Pos); 205 New.Data = string(Line, Pos+1); 206 207 // Add to configuration list 208 if (pthread_mutex_lock(&Mutex) != 0) State(ERROR, "pthread_mutex_lock() failed in ConfigChanged()"); 209 List.push_back(New); 210 if (pthread_mutex_unlock(&Mutex) != 0) State(ERROR, "pthread_mutex_unlock() failed in ConfigChanged()"); 211 }; 212 } 213 143 214 144 215 // -
Evidence/DColl.cc
r199 r203 319 319 320 320 if (Text != NULL) { 321 // Replace all control characters by white space 322 for (int i=0; i<strlen(Text); i++) if (iscntrl(Text[i])) Text[i] = ' '; 321 // Replace new line by '\' and all other control characters by white space 322 for (int i=0; i<strlen(Text); i++) { 323 if (Text[i] == '\n') Text[i] = '\\'; 324 else if (iscntrl(Text[i])) Text[i] = ' '; 325 } 323 326 324 327 // Write to file
Note:
See TracChangeset
for help on using the changeset viewer.