source: Evidence/Config.cc @ 151

Last change on this file since 151 was 151, checked in by ogrimm, 11 years ago
DColl publishes also current data file name
File size: 5.1 KB
Line 
1/********************************************************************\
2
3  Configuration server for the Evidence Control System
4
5  - The configuration file is opened without buffering to catch changes
6    without closing/opening.
7  - The name of a configuration file can be given as command line argument
8  - 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.
13         
14  Oliver Grimm, November 2009
15
16\********************************************************************/
17
18#define DEFAULT_CONFIG "../config/Evidence.conf"
19#define SERVER_NAME "Config"
20
21#include "Evidence.h"
22
23#include <ctype.h>
24#include <sys/stat.h>
25#include <sys/inotify.h>
26
27//
28// Class derived from DimRpc
29//
30class EvidenceConfig: public DimRpc, public EvidenceServer {
31
32  private:
33    FILE *File; 
34    char *Buffer;
35    unsigned int BufferLength;
36    DimService *ConfigModified;
37    int ModifyTime;
38       
39    void rpcHandler();
40 
41  public:
42    EvidenceConfig(const char *);
43    ~EvidenceConfig();
44       
45        void ConfigChanged(); 
46};
47
48// Constructor
49EvidenceConfig::EvidenceConfig(const char *Filename):
50        DimRpc("ConfigRequest", "C", "C"), EvidenceServer(SERVER_NAME) {
51
52  // Open configuration file
53  if ((File = fopen(Filename, "r")) == NULL) {
54    State(FATAL, "Could not open configuration file '%s' (%s)\n", Filename, strerror(errno));
55  }
56
57  // Create DIM service to indicate changes of configuration file
58  struct stat Stat;
59  if (stat(Filename, &Stat) == -1) {
60    State(WARN, "Could not read last modification time of configuration file '%s' (%s)", Filename, strerror(errno));
61        ModifyTime = 0;
62  }
63  else ModifyTime = Stat.st_mtime;   
64  ConfigModified = new DimService (SERVER_NAME"/ModifyTime", ModifyTime);
65
66  // Disable buffering, so file modifications are immediately seen
67  if (setvbuf(File, NULL, _IONBF, 0) != 0) {
68    State(WARN, "Error setting configuration file '%s' to unbuffered mode", Filename);
69  }
70   
71  Buffer = NULL;    // Will be allocated in rpcHandler()
72  BufferLength = 0;
73}
74
75// Destructor
76EvidenceConfig::~EvidenceConfig() {
77
78  if (File != NULL) fclose(File); 
79  delete[] Buffer;
80}
81
82// Implementation of response to configuration request
83void EvidenceConfig::rpcHandler() {
84
85  char *Token1,*Token2,*Token3, *Request = getString();
86  struct stat FileStatus;
87 
88  // Check if Buffer[] is large enough to hold full file, enlarge if necessary
89  if (fstat(fileno(File), &FileStatus) == -1) {
90     State(FATAL, "Could not determine size of configuration file to allocate buffer (%s)", strerror(errno));
91  }
92  else if(BufferLength < FileStatus.st_size) {
93    delete[] Buffer;
94    Buffer = new char [FileStatus.st_size];
95    BufferLength = FileStatus.st_size;   
96  }
97 
98  // Search for configuration item
99  rewind(File);
100  while (fgets(Buffer, BufferLength, File) != NULL) {
101   
102    // Combine lines that end with '+'
103    while (Buffer[strlen(Buffer)-2] == '+') {
104      if (fgets(Buffer+strlen(Buffer)-2, BufferLength-(strlen(Buffer)-2), File) == NULL) break;
105    }
106   
107    // Ignore comments
108    for (int i=0; i<strlen(Buffer); i++) if (Buffer[i] == '#') Buffer[i] = '\0';
109   
110    // Extract tokens
111    Token1 = strtok(Buffer, " \t:");
112    Token2 = strtok(NULL, " \t:");
113    Token3 = strtok(NULL, "\n");
114   
115    // Check if all tokens existing
116    if(Token1==NULL || Token2==NULL || Token3==NULL) continue;
117
118    // Check for match and then send data (removing trainlin whitespace)
119    if (strstr(Request, Token1)!=NULL && strstr(Request, Token2)!=NULL) {
120          while (isspace(*Token3) != 0) Token3++;
121      setData(Token3);
122      break;
123    }
124  }
125 
126  // If configuration data not found, send empty string
127  if (feof(File)!=0) setData((char *) "");
128 
129  State(INFO, "Client '%s' (ID %d) requested '%s'. Send '%s'.",
130                DimServer::getClientName(),
131                DimServer::getClientId(), 
132                Request, feof(File)!=0 ? "n/a" : Token3);
133}
134
135// Signalisation of configuration change
136void EvidenceConfig::ConfigChanged() {
137
138  ModifyTime = time(NULL);
139  ConfigModified->updateService();
140}
141
142//         
143// Declaring class static ensures destructor is called when exit() is invoked
144//
145int main(int argc, char *argv[]) {
146       
147  static EvidenceConfig Config(argc<2 ? DEFAULT_CONFIG : argv[1]);
148
149  int Notify;
150  struct inotify_event Event;
151 
152  if ((Notify = inotify_init()) == -1) {
153    Config.State(EvidenceConfig::WARN, "inotify_init() failed, cannot monitor changes of configuration file (%s)\n", strerror(errno));
154  }
155  else if (inotify_add_watch(Notify, argc<2 ? DEFAULT_CONFIG : argv[1], IN_MODIFY) == -1) { 
156      Config.State(EvidenceConfig::WARN, "Could not set inotify watch on configuration file (%s)\n", strerror(errno));
157          close(Notify);
158          Notify = -1;
159  }
160
161  // Sleep until file changes or signal caught
162  while (!EvidenceServer::ExitRequest) {
163    if (Notify != -1) {
164          read(Notify, &Event, sizeof(Event));
165          Config.ConfigChanged();
166        }
167    else pause();         
168  }
169 
170  if (Notify != -1) close(Notify);
171}
Note: See TracBrowser for help on using the repository browser.