1 | /********************************************************************\
|
---|
2 |
|
---|
3 | Central data collector of the Evidence Control System
|
---|
4 |
|
---|
5 | - DColl subscribes to all services given by the configuration
|
---|
6 | server and writes these to the data file at every update.
|
---|
7 | - For each service, it creates a new service with '.hist' appended that
|
---|
8 | contains a history of events kept within a ring buffer. Each entry will
|
---|
9 | be the result of a conversion to double of the text written to the data file.
|
---|
10 | - The command 'DColl/Log' writes the associated string to the log
|
---|
11 | file specified in the configuration.
|
---|
12 |
|
---|
13 | Oliver Grimm, December 2009
|
---|
14 |
|
---|
15 | \********************************************************************/
|
---|
16 |
|
---|
17 | #define SERVER_NAME "DColl"
|
---|
18 |
|
---|
19 | #include "../Evidence.h"
|
---|
20 |
|
---|
21 | #define NO_LINK "__&DIM&NOLINK&__" // for checking if DIMserver is alive
|
---|
22 |
|
---|
23 | //
|
---|
24 | // Class declaration
|
---|
25 | //
|
---|
26 | class DataHandler: public DimClient, public DimCommand,
|
---|
27 | public DimBrowser, public EvidenceServer {
|
---|
28 | private:
|
---|
29 | pthread_mutex_t DataMutex;
|
---|
30 | pthread_mutex_t LogMutex;
|
---|
31 |
|
---|
32 | unsigned int NumItems;
|
---|
33 | FILE *DataFile;
|
---|
34 | FILE *LogFile;
|
---|
35 | char *Filename;
|
---|
36 |
|
---|
37 | DimStampedInfo **DataItem;
|
---|
38 | DimService **HistService;
|
---|
39 | int HistSize;
|
---|
40 | struct EvidenceHistoryItem **HistBuffer;
|
---|
41 | int *HistPointer;
|
---|
42 |
|
---|
43 | void infoHandler();
|
---|
44 | void commandHandler();
|
---|
45 | bool ReallocMem(void *&, int);
|
---|
46 |
|
---|
47 | public:
|
---|
48 | DataHandler();
|
---|
49 | ~DataHandler();
|
---|
50 | };
|
---|
51 |
|
---|
52 | //
|
---|
53 | // Constructor
|
---|
54 | //
|
---|
55 | DataHandler::DataHandler(): DimCommand((char *) "DColl/Log", (char *) "C"), EvidenceServer(SERVER_NAME) {
|
---|
56 |
|
---|
57 | // Initialization to prevent freeing unallocated memory
|
---|
58 | DataFile = NULL;
|
---|
59 | Filename = NULL;
|
---|
60 |
|
---|
61 | DataItem = NULL;
|
---|
62 | HistService = NULL;
|
---|
63 | HistBuffer = NULL;
|
---|
64 | HistPointer = NULL;
|
---|
65 |
|
---|
66 | // Request configuration data
|
---|
67 | char *Items = GetConfig(SERVER_NAME " items");
|
---|
68 | char *DataDir = GetConfig(SERVER_NAME " datadir");
|
---|
69 | char *Logname = GetConfig(SERVER_NAME " logfile");
|
---|
70 | HistSize = atoi(GetConfig(SERVER_NAME " histsize"));
|
---|
71 | if (HistSize < 1) HistSize = 1; // Minimum one items
|
---|
72 |
|
---|
73 | // Create mutex for thread synchronization
|
---|
74 | if ((errno=pthread_mutex_init(&DataMutex, NULL)) != 0) {
|
---|
75 | Msg(FATAL, "pthread_mutex_init() failed for data file (%s)", strerror(errno));
|
---|
76 | }
|
---|
77 | if ((errno=pthread_mutex_init(&LogMutex, NULL)) != 0) {
|
---|
78 | Msg(FATAL, "pthread_mutex_init() failed for log file (%s)", strerror(errno));
|
---|
79 | }
|
---|
80 |
|
---|
81 | // Interpret DIM services to observe and prepare history buffer
|
---|
82 | char *Buf, *ServiceName, *Format;
|
---|
83 | int NumServices;
|
---|
84 | NumItems = 0;
|
---|
85 | char *NextToken = strtok(Items, " \t");
|
---|
86 | while (NextToken != NULL) {
|
---|
87 | NumServices = getServices(NextToken);
|
---|
88 | for (int j=0; j<NumServices; j++) {
|
---|
89 | if (getNextService(ServiceName, Format) == DimSERVICE) {
|
---|
90 |
|
---|
91 | // Check if already subsubed to this service
|
---|
92 | for (int i=0; i<NumItems; i++) {
|
---|
93 | if(strcmp(ServiceName, DataItem[i]->getName()) == 0) continue;
|
---|
94 | }
|
---|
95 |
|
---|
96 | // Increase capacity of arrays
|
---|
97 | if (!ReallocMem((void *&) DataItem, NumItems+1)) continue;
|
---|
98 | if (!ReallocMem((void *&) HistService, NumItems+1)) continue;
|
---|
99 | if (!ReallocMem((void *&) HistBuffer, NumItems+1)) continue;
|
---|
100 | if (!ReallocMem((void *&) HistPointer, NumItems+1)) continue;
|
---|
101 |
|
---|
102 | // Subscribe to service
|
---|
103 | DataItem[NumItems] = new DimStampedInfo(ServiceName, (char *) NO_LINK, this);
|
---|
104 |
|
---|
105 | // Create history service
|
---|
106 | HistBuffer[NumItems] = new struct EvidenceHistoryItem [HistSize];
|
---|
107 | memset(HistBuffer[NumItems], 0, HistSize*sizeof(EvidenceHistoryItem));
|
---|
108 | HistPointer[NumItems] = 0;
|
---|
109 |
|
---|
110 | if (asprintf(&Buf, "%s.hist", ServiceName) == -1) {
|
---|
111 | Msg(ERROR, "Could not create Hist service for %s because asprintf() failed", ServiceName);
|
---|
112 | }
|
---|
113 | else {
|
---|
114 | HistService[NumItems] = new DimService (Buf, (char *) "C",
|
---|
115 | HistBuffer[NumItems], HistSize*sizeof(EvidenceHistoryItem));
|
---|
116 | free(Buf);
|
---|
117 | }
|
---|
118 | NumItems++;
|
---|
119 | }
|
---|
120 | }
|
---|
121 | NextToken = strtok(NULL, " \t");
|
---|
122 | }
|
---|
123 |
|
---|
124 | // Open data file
|
---|
125 | time_t rawtime = time(NULL);
|
---|
126 | struct tm * timeinfo = gmtime(&rawtime);
|
---|
127 | if(timeinfo->tm_hour >= 13) rawtime += 12*60*60;
|
---|
128 | timeinfo = gmtime(&rawtime);
|
---|
129 |
|
---|
130 | if (asprintf(&Filename, "%s/%d%02d%02d.slow", DataDir, timeinfo->tm_year+1900, timeinfo->tm_mon+1, timeinfo->tm_mday) == -1) {
|
---|
131 | Filename = NULL;
|
---|
132 | Msg(FATAL, "Could not create filename with asprintf()(%s)", strerror(errno));
|
---|
133 | }
|
---|
134 | if ((DataFile = fopen(Filename, "a")) == NULL) {
|
---|
135 | Msg(FATAL, "Could not open data file '%s' (%s)", Filename, strerror(errno));
|
---|
136 | }
|
---|
137 |
|
---|
138 | // Open log file
|
---|
139 | if ((LogFile = fopen(Logname, "a")) == NULL) {
|
---|
140 | Msg(FATAL, "Could not open log file '%s' (%s)", Logname, strerror(errno));
|
---|
141 | }
|
---|
142 |
|
---|
143 | }
|
---|
144 |
|
---|
145 | //
|
---|
146 | // Destructor: Close files and free memory
|
---|
147 | //
|
---|
148 | DataHandler::~DataHandler() {
|
---|
149 |
|
---|
150 | // Close files
|
---|
151 | if (LogFile != NULL && fclose(LogFile) != 0) {
|
---|
152 | Msg(ERROR, "Could not close log file (%s)", strerror(errno));
|
---|
153 | }
|
---|
154 | if (DataFile != NULL && fclose(DataFile) != 0) {
|
---|
155 | Msg(ERROR, "Error: Could not close data file (%s)", strerror(errno));
|
---|
156 | }
|
---|
157 |
|
---|
158 | // Free all memory
|
---|
159 | for (int i=0; i<NumItems; i++) {
|
---|
160 | delete[] HistBuffer[i];
|
---|
161 | delete DataItem[i];
|
---|
162 | }
|
---|
163 |
|
---|
164 | free(Filename);
|
---|
165 | free(HistService);
|
---|
166 | free(HistPointer);
|
---|
167 | free(HistBuffer);
|
---|
168 | free(DataItem);
|
---|
169 |
|
---|
170 | // Destroy mutex
|
---|
171 | pthread_mutex_destroy (&LogMutex);
|
---|
172 | pthread_mutex_destroy (&DataMutex);
|
---|
173 | }
|
---|
174 |
|
---|
175 | //
|
---|
176 | // Implementation of data handling
|
---|
177 | //
|
---|
178 | // More than one infoHandler() might run in parallel, therefore
|
---|
179 | // the mutex mechanism is used to serialize writing to the file
|
---|
180 | void DataHandler::infoHandler() {
|
---|
181 |
|
---|
182 | DimInfo *Info = getInfo();
|
---|
183 |
|
---|
184 | // Check if service actually available, if it contains data and if data file is open
|
---|
185 | if (Info->getSize()==strlen(NO_LINK)+1 && strcmp(Info->getString(), NO_LINK)==0) return;
|
---|
186 | if (Info->getSize() == 0 || DataFile == NULL) return;
|
---|
187 |
|
---|
188 | // Identify index of service
|
---|
189 | int Service;
|
---|
190 | for (Service=0; Service<NumItems; Service++) if (Info == DataItem[Service]) break;
|
---|
191 | if (Service == NumItems) return; // Not found: should never happen
|
---|
192 |
|
---|
193 | pthread_mutex_lock(&DataMutex);
|
---|
194 |
|
---|
195 | // Write data header
|
---|
196 | time_t RawTime = Info->getTimestamp();
|
---|
197 | struct tm *TM = localtime(&RawTime);
|
---|
198 |
|
---|
199 | fprintf(DataFile, "%s %d %d %d %d %d %d %d %lu ", Info->getName(), TM->tm_year+1900, TM->tm_mon+1, TM->tm_mday, TM->tm_hour, TM->tm_min, TM->tm_sec, Info->getTimestampMillisecs(), Info->getTimestamp());
|
---|
200 |
|
---|
201 | // Translate info data into ASCII and write to file and to history buffer
|
---|
202 | char *Text = EvidenceServer::ToString(Info);
|
---|
203 | if (Text != NULL) {
|
---|
204 | fprintf(DataFile, "%s\n", Text);
|
---|
205 |
|
---|
206 | HistBuffer[Service][HistPointer[Service]].Seconds = Info->getTimestamp();
|
---|
207 | HistBuffer[Service][HistPointer[Service]].Value = atof(Text);
|
---|
208 | HistService[Service]->updateService();
|
---|
209 | HistPointer[Service]++;
|
---|
210 | if (HistPointer[Service] >= HistSize) HistPointer[Service] = 0;
|
---|
211 |
|
---|
212 | free(Text);
|
---|
213 | }
|
---|
214 | else fprintf(DataFile, "Cannot interpret format identifier\n");
|
---|
215 |
|
---|
216 | fflush(DataFile);
|
---|
217 | if(ferror(DataFile)) Msg(ERROR, "Error writing to data file (%s)", strerror(errno));
|
---|
218 |
|
---|
219 | pthread_mutex_unlock(&DataMutex);
|
---|
220 | }
|
---|
221 |
|
---|
222 | //
|
---|
223 | // Implementation of log writing (the only command is 'DColl/Log')
|
---|
224 | //
|
---|
225 | void DataHandler::commandHandler() {
|
---|
226 |
|
---|
227 | if (LogFile == NULL) return; // Handler might be called before file is opened
|
---|
228 |
|
---|
229 | pthread_mutex_lock(&LogMutex);
|
---|
230 |
|
---|
231 | time_t RawTime = time(NULL);
|
---|
232 | struct tm *TM = localtime(&RawTime);
|
---|
233 |
|
---|
234 | fprintf(LogFile, "%d/%d/%d %d:%d:%d: %s\n",
|
---|
235 | TM->tm_mday, TM->tm_mon+1, TM->tm_year+1900,
|
---|
236 | TM->tm_hour, TM->tm_min, TM->tm_sec, getString());
|
---|
237 |
|
---|
238 | fflush(LogFile);
|
---|
239 | if(ferror(LogFile)) Msg(ERROR, "Error writing to log file (%s)", strerror(errno));
|
---|
240 | pthread_mutex_unlock(&LogMutex);
|
---|
241 | }
|
---|
242 |
|
---|
243 |
|
---|
244 | //
|
---|
245 | // Implementation of memory re-allocation for pointer arrays
|
---|
246 | //
|
---|
247 | bool DataHandler::ReallocMem(void *&Memory, int Size) {
|
---|
248 |
|
---|
249 | void *NewMem = realloc(Memory, Size*sizeof(void *));
|
---|
250 |
|
---|
251 | if (NewMem != NULL) {
|
---|
252 | Memory = NewMem;
|
---|
253 | return true;
|
---|
254 | }
|
---|
255 | else {
|
---|
256 | Msg(ERROR, "Could not allocate memory ()", strerror(errno));
|
---|
257 | return false;
|
---|
258 | }
|
---|
259 | }
|
---|
260 |
|
---|
261 | //
|
---|
262 | // Main program
|
---|
263 | //
|
---|
264 | int main() {
|
---|
265 |
|
---|
266 | // Static ensures calling of destructor by exit()
|
---|
267 | static DataHandler Data;
|
---|
268 |
|
---|
269 | pause(); // Sleep until signal caught
|
---|
270 | }
|
---|