source: Evidence/Evidence.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: 5.8 KB
Line 
1/********************************************************************\
2
3  General code to start a server of the Evidence Control System
4 
5  - The server is started with the given name.
6  - DIM exit and error handlers are implemented.
7  - The Status service is published.
8    It can be updated with the Msg() method. The text will also be logged.
9  - Configuration data can be requested by GetConfig().
10  - Signal handlers to ignore common signals are installed.
11    These signals will then cause pause() to return which can be used
12        by the application to terminate gracefully.
13  - The static method ToString() converts the contents of a
14    DIMInfo service into text
15       
16  All memory allocated by the non-static methods will be freed by the
17  class destructor.
18 
19  Oliver Grimm, December 2009
20 
21\********************************************************************/
22
23#include "Evidence.h"
24
25bool EvidenceServer::ExitRequest = false;
26
27// Constructor starts server with given name
28EvidenceServer::EvidenceServer(const char *Name) {
29
30  // Initialize
31  Status = NULL;
32  MsgBuffer = NULL;
33  ConfigList = NULL;
34  ConfigNum = 0;
35 
36  // Catch some signals
37  signal(SIGQUIT, &SignalHandler);  // CTRL-Backspace
38  signal(SIGTERM, &SignalHandler);  // Termination signal
39  signal(SIGINT, &SignalHandler);   // CTRL-C
40  signal(SIGHUP, &SignalHandler);   // Terminal closed
41 
42  // Create server name
43  if (asprintf(&ServerName, "%s/Status", Name) == -1) {
44    ServerName = NULL;
45    Msg(FATAL, "Could not generate service name, asprintf() failed");
46  }
47 
48  // Start server
49  static char InitMsg[] = "OK" "\0" "0";
50  Status = new DimService(ServerName, (char *) "C", InitMsg, sizeof(InitMsg));
51  DimServer::start(Name);
52  DimServer::addExitHandler(this);
53 
54  Msg(INFO, "Server started");
55}
56
57// Destructor: Frees all buffers
58EvidenceServer::~EvidenceServer() {
59
60  free(ServerName);
61  free(MsgBuffer);
62 
63  for (unsigned int i=0; i<ConfigNum; i++) {
64    delete *((DimRpcInfo **) ConfigList + i);
65  }
66  free(ConfigList);
67}
68
69// DIM exit handler
70void EvidenceServer::exitHandler(int Code) {
71  Msg(INFO, "Server stopped (DIM exit code %d)", Code);
72  exit(EXIT_SUCCESS);
73}
74
75// DIM error handler
76void EvidenceServer::errorHandler(int Severity, int Code, char *Message) {   
77  Msg(ERROR, "%s (DIM Error, code %d, severity %d)\n", Message, Code, Severity);
78}
79
80// Print message to screen, to log and to status
81//
82// The message format is special: after the string-terminating '\0'
83// the Severity is given, terminated by another '\0'
84// The buffer must have the same lifetime as the DIM service.
85// If Severity is FATAL, exit() will be invoked.
86void EvidenceServer::Msg(MsgType Severity, const char *Format, ...) {
87
88  char *TmpBuffer;
89  int Size;
90 
91  static char DefaultMsg[]="vasprintf() or asprintf() failed, cannot process message" "\0" "2";   // Severity 'Error'
92   
93  // Assemble message from application
94  va_list ArgumentPointer;
95  va_start(ArgumentPointer, Format);
96  if (vasprintf(&TmpBuffer, Format, ArgumentPointer) == -1) TmpBuffer = NULL;
97  va_end(ArgumentPointer);
98
99  // Free previous message buffer if allocated dynamically
100  if (MsgBuffer != DefaultMsg) free(MsgBuffer);
101 
102  // Assemble final message including headers and Severity encoding
103  if (TmpBuffer == NULL) Size = -1;
104  else Size = asprintf(&MsgBuffer, "%s: %s%s*%d", ServerName,
105                (Severity==FATAL) ? "(Fatal) ":"", TmpBuffer,
106                (unsigned char) Severity);
107  free(TmpBuffer);
108
109  // If memory could not be allocated, show default message,
110  // otherwise replace '*' by '0' for severity encoding         
111  if (Size == -1) {
112    MsgBuffer = DefaultMsg;
113        Size = sizeof(DefaultMsg) - 1;
114  }
115  else *(strrchr(MsgBuffer, '*')) = '\0';
116
117  // Send message to console, log file and update DIM status service
118  printf("%s\n", MsgBuffer);
119  DimClient::sendCommand("DColl/Log", MsgBuffer);
120  if (Status != NULL) Status->updateService(MsgBuffer, Size+1);
121
122  // Terminate if message type is fatal
123  if (Severity == FATAL) exit(EXIT_FAILURE);
124}
125
126// Get configuration data (program terminates if data is missing)
127//
128// The memory allocated by all calls to this function will be freed by
129// the destructor.
130char* EvidenceServer::GetConfig(const char *Item) {
131
132  // Enlarge memory to hold new pointer
133  DimRpcInfo **Config = (DimRpcInfo **) realloc(ConfigList, sizeof(void *) * (++ConfigNum));
134  if (Config == NULL) {
135    Msg(WARN, "Could not realloc() memory for DimRpcInfo list (%s)", strerror(errno));
136    ConfigNum--; 
137  }
138  else ConfigList = (void *) Config;
139 
140  // Advance array pointer to position for new DimRpcInfo pointer
141  Config += ConfigNum - 1;
142 
143  // Make configuration request
144  *Config = new DimRpcInfo((char *) "ConfigRequest", (char *) "");
145  (*Config)->setData((char *) Item);
146
147  // Terminate if not successful
148  if (strlen((*Config)->getString()) == 0) {
149    Msg(FATAL, "Missing configuration data '%s'", Item);
150  }
151
152  return (*Config)->getString();
153}
154
155
156// ====== Static methods ======
157
158// Signal handler (causes pause() to return)
159void EvidenceServer::SignalHandler(int) {
160  EvidenceServer::ExitRequest = true;
161}
162
163// Translates DIMInfo to string (memory has to be freed by caller)
164char *EvidenceServer::ToString(DimInfo *Item) {
165
166  char *Text;
167  int R;
168 
169  // Cannot handle complex data formats
170  if (strlen(Item->getFormat()) != 1) return NULL;
171 
172  // Interpret format
173  switch (*(Item->getFormat())) {
174    case 'I':  R = asprintf(&Text, "%d", Item->getInt());   break;
175    case 'C':  R = asprintf(&Text, "%s", Item->getString());   break;
176    case 'S':  R = asprintf(&Text, "%hd", Item->getShort());   break;
177    case 'F':  R = asprintf(&Text, "%.3f", Item->getFloat());   break;
178    case 'D':  R = asprintf(&Text, "%.3f", Item->getDouble());   break;
179    case 'X':  R = asprintf(&Text, "%lld", Item->getLonglong());   break;
180    default: return NULL;
181  }
182
183  // Check if aprintf() worked OK
184  if (R != -1) return Text;
185  else return NULL;
186}
Note: See TracBrowser for help on using the repository browser.