source: Evidence/Config/Config.cc @ 127

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